Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 386 Accepted Submission(s): 190
1 3 1 2 0 2 3 1
1 in the sample. $ans_1=2$ $ans_2=2$ $ans_3=1$ $2~xor~2~xor~1=1$,so you need to output 1.
连通路径,并查集应用。
bestcoder比赛的时候,一直以为0是表示没有路,而1表示有路,最近的当然是1的那条边咯~。然后就是经验不足带来的无限WA的后果。很忧伤,很忧伤。。。。。。。。。。
这里大概题意是这样的:0边权和1边权都表示有路,但是0当然比1近,所以我们这里只考虑0的路,并不考虑1的路,因为我们要找的是当前点能找到的近的点。如果我要从这个点向周围找点,因为0边权进,所以我会去放弃1边权的点。所以这里当边权为0的时候,连通两点,直接不考虑1的路。
int n; scanf("%d",&n); for(int i=1;i<=n;i++) { f[i]=i; j[i]=1;//集合数。 } for(int i=0;i<n-1;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); if(c==0) merge(x,y); }
然后我们这里就要涉及一个找到点的个数的问题。我们这里用一个数组j表示。
当连通两点的时候,一个集合的点的数量,给另一个集合。
int find(int x) { return f[x]==x?x:(f[x] = find(f[x])); } void merge(int a,int b) { int A,B; A=find(a); B=find(b); if(A!=B) { f[A]=B;//这里表示A集合给了B(也可能是点) j[B]+=j[A];//然后把A集合的数量也加到B上、 } }
然后最后每一个点都找到自己的祖宗,询问有多少个点距离自己都是0.然后每一个都xor一下就可以了~。
最后上完整的AC代码:
#include<stdio.h> #include<string.h> using namespace std; int f[100010]; int j[100010]; int find(int x) { return f[x]==x?x:(f[x] = find(f[x])); } void merge(int a,int b) { int A,B; A=find(a); B=find(b); if(A!=B) { f[A]=B; j[B]+=j[A]; } } int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { f[i]=i; j[i]=1; } for(int i=0;i<n-1;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); if(c==0) merge(x,y); } int output=j[find(1)]; for(int i=2;i<=n;i++) { output^=j[find(i)]; } printf("%d\n",output); } }