题解:P8971 『GROI-R1』 虹色的彼岸花
P8971 『GROI-R1』 虹色的彼岸花 题解
题目传送门
分析部分:
对于一条边连接的两个点,如果这条边有边权,当其中一个点的点权确定时,另一个点的点权也会确定;如果这条边无边权,两个点的点权相互之间不会有影响。因此可以将无边权的边忽略,将这一棵树看作森林,对其中的每棵树进行处理。
对于一棵树,只要确定了一个点的点权,就可以确定通过边权计算出其他点的点权。因此我们可以从一点开始访问,令其值为
我们可以从最开始的点进行 dfs。对于一个点 一年半前极差的取名习惯),若
代码部分:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,mod=1e9+7;
struct node{
int to,next,w;
}e[N<<1];
long long l,r;
long long n,t,cnt,ans;
long long h[N];
long long ll,rr,x,y,op,w;
bool vis[N];
void Link(int x,int y,int w){
e[++cnt].to=y;
e[cnt].next=h[x];
e[cnt].w=w;
h[x]=cnt;
}
void dfs(int x,int k,int sign){
vis[x]=true;
long long nl=l-k,nr=r-k;//解不等式
if(sign==-1)swap(nl,nr),nl=-nl,nr=-nr;
ll=max(ll,nl),rr=min(rr,nr);//更新左极值、右极值
for(int i=h[x];i;i=e[i].next){
if(!vis[e[i].to])
dfs(e[i].to,e[i].w-k,-sign);//计算k和sign
}
}
int main(){
cin>>t;
while(t--){
cin>>n>>l>>r;
memset(vis,false,sizeof(vis));//多测清空
memset(e,0,sizeof(e));
memset(h,0,sizeof(h));
cnt=0;
ans=1;
for(int i=1;i<=n-1;i++){
cin>>op>>x>>y;
if(op==1)cin>>w;
else continue;//忽略无边权的边
Link(x,y,w);
Link(y,x,w);
}
for(int i=1;i<=n;i++){
ll=l,rr=r;
if(!vis[i]){
dfs(i,0,1);//从自己开始,自己的k是0,sign是1
if(rr<ll)ans*=0;//更新范围
else ans=ans*(rr-ll+1)%mod;
}
}
cout<<ans<<endl;
}
return 0;
}