tree
Accepts: 143
Submissions: 807
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
有一个树(n个点, n−1条边的联通图),点标号从1~n,树的边权是0或1.求离每个点最近的点个数(包括自己).
输入描述
第一行一个数字T,表示T组数据. 对于每组数据,第一行是一个n,表示点个数,接下来n−1,每行三个整数u,v,w,表示一条边连接的两个点和边权. T=50,1≤n≤100000,1≤u,v≤n,0≤w≤1.
输出描述
对于每组数据,输出答案. 考虑到输出规模过大,设ansi表示第i个点的答案.你只需输出ans1 xor ans2 xor ans3.. xor ansn即可.
输入样例
1 3 1 2 0 2 3 1
输出样例
1
Hint
ans1=2 ans2=2 ans3=1 2 xor 2 xor 1=1, 因此输出1.
官方题解:
把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小.
开一个并查集,每次读到边权是0的边就合并.最后Ansi=size[findset(i)],size表示每个并查集根的size.
AC代码:
#include<iostream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<cstdio> using namespace std; #define T 100010 typedef long long ll; int par[T]; int find(int x) { int tmp = x; while(x!=par[x]) { x = par[x]; } return x; } int main() { #ifdef zsc freopen("input.txt","r",stdin); #endif int N,i; int n,m,j,k,u,v,w; scanf("%d",&N); while(N--) { scanf("%d",&n); int V[T]; for(i=0;i<=n;++i){ par[i] = i; V[i] = 1; } for(i=0;i<n-1;++i){ scanf("%d%d%d",&u,&v,&w); if(w==0){ int tx = find(u),ty = find(v); if(tx!=ty){ par[tx] = ty; V[ty] += V[tx]; } } } k = 0; for(i=1;i<=n;++i){ k ^= V[find(i)]; } printf("%d\n",k); } return 0; }