ICPC2017 Urumqi A Possible Tree(带权并查集)

题目链接:https://nanti.jisuanke.com/t/28968

 

题目大意: n个数字c个条件,然后n-1条边,问从上到下最多满足几个条件

 

题目思路:树上的异或,两点间无论怎么走都是两者最短路径上的异或和。r[i]表示i点到根节点的路径异或和。所以每次查条件的时候,如果两个人在同一链,那他俩有同一根节点,那么两者到根节点异或和的异或就是两者最近路上的异或。如果不是同一条链,那么就让二者合并。路径压缩的时候就把一条链上,同时更新r[i]

 

以下是代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define MAXN 100005
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
int pre[MAXN];
ll r[MAXN];
int Find(int x){if(x==pre[x])return x;int root=Find(pre[x]);r[x]^=r[pre[x]];return pre[x]=root;
}
int main()
{int t,n,c,x,y;ll z;scanf("%d",&t);while(t--){scanf("%d%d",&n,&c);rep(i,1,n){pre[i]=i;r[i]=0;if(i==n)break;scanf("%d%d",&x,&y);}int ans=n+1;rep(i,1,c){scanf("%d%d%d",&x,&y,&z);if(ans!=n+1)continue;int xx=Find(x),yy=Find(y);if(xx==yy&&(r[x]^r[y])!=z)ans=i;else{pre[xx]=yy;r[xx]=r[x]^r[y]^z;}}printf("%d\n",ans-1);}return 0;
}