BC68(HD5606) 并查集+求集合元素
tree
Accepts: 143
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
有一个树(nn个点, n-1n−1条边的联通图),点标号从11~nn,树的边权是00或11.求离每个点最近的点个数(包括自己).
输入描述
第一行一个数字TT,表示TT组数据.
对于每组数据,第一行是一个nn,表示点个数,接下来n-1n−1,每行三个整数u,v,wu,v,w,表示一条边连接的两个点和边权.
T = 50,1 \leq n \leq 100000, 1 \leq u,v \leq n,0 \leq w \leq 1T=50,1≤n≤100000,1≤u,v≤n,0≤w≤1.
输出描述
对于每组数据,输出答案.
考虑到输出规模过大,设ans_iansi表示第ii个点的答案.你只需输出ans_1 \ xor \ ans_2 \ xor \ ans_3.. \ xor \ ans_nans1 xor ans2 xor ans3.. xor ansn即可.
输入样例
1 3 1 2 0 2 3 1
输出样例
1
Hint
ans_1 = 2ans1=2
ans_2 = 2ans2=2
ans_3 = 1ans3=1
2 \ xor \ 2 \ xor \ 1=12 xor 2 xor 1=1, 因此输出11.
马丹!!我想骂人!刚开始做这道题就开始开了一个数组求每一个为0的两个点的数量,最后猛然发现如果三个数都是0答案就不对,然后有想到了深搜,用vector,存与之相连为0的点,写到一半,发现又不对!马丹,猛然想起就是并查集啊,把为0的点放在一起,就是就每个集合中数的个数嘛!敲了不到10分钟敲完,卡在8:45提交了,WA了,擦!猛然发现一个细节给忽略了,果断改了,8:46了。。。呵呵呵呵。。刚才提交a了,擦!太弱了,伤心的是又掉rating了....
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 #include <vector> 6 using namespace std; 7 const int MAX = 100000 + 10; 8 int num[MAX],father[MAX]; 9 int find_father(int x) 10 { 11 int r = x; 12 while(r != father[r]) 13 r = father[r]; 14 int i = x,j; 15 while(r != father[i]) 16 { 17 j = father[i]; 18 father[i] = r; 19 //num[r] += num[father[i]] 擦!就是这!没必要啊,以为此时num[r]中肯定含有num[father[i]],因为这只是跟新直系跟节点,数量并不需修改!!! 20 i = j; 21 } 22 return r; 23 } 24 void Union(int x, int y) 25 { 26 int fx = find_father(x); 27 int fy = find_father(y); 28 if(fx != fy) 29 { 30 father[fx] = fy; 31 num[fy] += num[fx]; 32 } 33 } 34 int main() 35 { 36 int t; 37 scanf("%d", &t); 38 while(t--) 39 { 40 int u,v,w,n; 41 scanf("%d", &n); 42 for(int i = 1; i <= n; i++) 43 { 44 father[i] = i; 45 num[i] = 1; 46 } 47 for(int i = 1; i < n; i++) 48 { 49 scanf("%d%d%d", &u,&v,&w); 50 if(w == 0) 51 { 52 Union(u,v); 53 } 54 } 55 int temp = find_father(1); 56 int ans = num[temp]; 57 58 for(int i = 2; i <= n; i++) 59 { 60 int fx = find_father(i); 61 ans = ans ^ num[fx]; 62 } 63 printf("%d\n",ans); 64 } 65 66 return 0; 67 }