首先这题和树的形态没有任何关系。
考虑没有限制的情况,答案就是2^(n-1)次方(每条边可以赋0或1)。
再考虑有一个限制,u,v之间的路径的奇偶性要为x:
1.如果u,v之间为一条之间相连的路径,那么u,v的奇偶性直接被固定,答案除2。
2.如果u,v之间有多条边,显然我们可以在u,v直接选出一个点mid,我们任意构造u,mid这条路径的奇偶性,那么mid,v这条路径的奇偶性就被确定了,而在这之前,mid,v这条路径的奇偶性也是可以随意构造的,设之前mid,v这条路径可以构造的方案数为sum,那么在确定u,mid这条路径的奇偶性后,mid,v这条路径的总方案数就降为sum/2,根据乘法原理,总方案数被除以2。
PS:对于两个相邻边,有(0,0)(0,1)(1,0)(1,1)显然奇偶性为1和为0的方案数是相等的,所以确定了一遍之后这一边才减少一半的答案。
所以将问题转换,如果一条路被限制,那么边就会被添加一条限制,我们可以用并查集维护连通块的个数,每个连通块内的奇偶性,那么如果连通块的个数为k,答案就是2^(k-1)(一开始有n个连通块,少一个连通块就相当于答案除一次2,因为边数只有n-1,所以连通块个数还要减1)。
当然还有第三种情况:
3.添加u,v是,u,v之间的路径已经经过一系列限制得出了奇偶性。此时我们要判断w与之前的限制是否矛盾,那么只要找出u,v所在的环的边,判断w是否和环的答案矛盾即可。
这题可以直接LCA+并查集做,但是我懒得打代码直接复制板子用LCT做了(其实用了LCT就没必要用并查集了)。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,mod=1e9+7;
int n,m,a[N],t[N][2],fa[N],lz[N],s[N];
void init()
{
memset(a,0,sizeof(a));
memset(t,0,sizeof(t));
memset(fa,0,sizeof(fa));
memset(lz,0,sizeof(lz));
memset(s,0,sizeof(s));
}
void pushup(int x)
{
s[x]=(s[t[x][0]]+s[t[x][1]]+a[x])&1;
}
void update(int x){
swap(t[x][0],t[x][1]);lz[x]^=1;}
void pushdown(int x)
{
if(lz[x])
{
if(t[x][0]) update(t[x][0]);
if(t[x][1]) update(t[x][1]);
lz[x]=0;
}
}
bool nroot(int x)
{
return t[fa[x]][0]==x|t[fa[x]][1]==x;
}
void Rotate(int x)
{
int y=fa[x],z=fa[y],k=(t[y][1]==x)^1;
if(nroot(y)) t[z][t[z][1]==y]=x;
t[y][k^1]=t[x][k];
if(t[x][k]) fa[t[x][k]]=y;
t[x][k]=y;
fa[y]=x;
fa[x]=z;
pushup(y);
}
int st[N];
void splay(int x)
{
int y=x,z=0;
st[++z]=y;
while(nroot(y)) st[++z]=y=fa[y];
while(z) pushdown(st[z--]);
while(nroot(x))
{
y=fa[x],z=fa[y];
if(nroot(y)) Rotate((t[y][1]==x)^(t[z][1]==y)?x:y);
Rotate(x);
}
pushup(x);
}
void access(int x)
{
for(int y=0;x;x=fa[y=x])
{
splay(x);t[x][1]=y;pushup(x);
}
}
void makeroot(int x)
{
access(x);splay(x);update(x);
}
int findroot(int x)
{
access(x);splay(x);
while(t[x][0]) pushdown(x),x=t[x][0];
splay(x);
return x;
}
void link(int x,int y)
{
makeroot(x);
fa[x]=y;
}
void cut(int x,int y)
{
makeroot(x);
if(findroot(y)==x&&fa[y]==x&&!t[y][0])
{
fa[y]=t[x][1]=0;
pushup(x);
}
}
void split(int x,int y)
{
makeroot(x);
access(y);splay(y);
}
bool judge(int u,int v,int w)
{
split(u,v);
return s[v]==w;
}
int f[N],p[N];
int getf(int x){
return f[x]==x?x:f[x]=getf(f[x]);}
int main()
{
p[0]=1;
for(int i=1;i<N;i++) p[i]=p[i-1]*2%mod;
int t;scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<n;i++)
{
int u,v;scanf("%d%d",&u,&v);
}
bool flag=true;
for(int i=1;i<=m;i++)
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);
int fu=getf(u),fv=getf(v);
if(fu==fv)
{
if(flag&&!judge(u,v,w)) flag=false;
continue;
}
f[fu]=fv;
a[i+n]=w;
link(u,i+n);link(i+n,v);
}
if(!flag) printf("0\n");
else
{
int ans=0;
for(int i=1;i<=n;i++)
if(f[i]==i) ans++;
printf("%d\n",p[ans-1]);
}
}
}