题目大意:
有一棵树,有n个结点,已知树的结构,不知道树的权值,给出树的n-1条边,给m次询问,每次询问代表节点a到节点b的权值的异或和是否为c,求最多能满足多少组这样的询问。
题解:
据大佬们说是带权并查集的裸题.....诶还是太菜
给的树的n-1条边并没有什么卵用,n-1个点,两个节点之间的路径必然是唯一的
①对于每次询问,并查集逐渐完善这棵树。
②用sum[i]表示i到根节点所有边权的异或和。
③并查集维护这个异或和。
④每次询问都进行判断,如果a,b根节点相同,看一下sum[x]^sum[y]是否等于c。如果不相同,就他们并起来,更新sum[fa]。
sum[fx]=sum[x]^val^sum[y];
这句话是说
#include<bits/stdc++.h>
#include<cstring>
using namespace std;
typedef long long ll;
int fa[100010],sum[100010];
int Find(int x)
{
if(fa[x]==x)return x;
int pre=fa[x];
if(fa[x]!=x)
{
fa[x]=Find(fa[x]);
sum[x]=sum[x]^sum[pre];
}
return fa[x];//是否需要带路径压缩还要考虑一下,有时带了会超时
}
int main()
{
//freopen("input.txt","r",stdin);
int n,c,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&c);
int x,y,val;
for(int i=1;i<=n-1;++i)
scanf("%d%d",&x,&y);
for(int i=0;i<=n;i++)
{
fa[i]=i;
sum[i]=0;
}
int ans=c+1;
for(int i=1;i<=c;++i)
{
scanf("%d%d%d",&x,&y,&val);
if(ans!=c+1)continue;
int fx=Find(x);
int fy=Find(y);
if(fx!=fy)
{
fa[fx]=fy;
sum[fx]=sum[x]^val^sum[y];
}
else//fx==fy
{
if((sum[x]^sum[y])!=val)
ans=i-1;
}
}
printf("%d\n",ans);
}
return 0;
}