问题描述
有一个树(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
有一个树(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.
首先因为求的是距离最近的点的个数,自己与自己的距离为0,
所以当前只有可能到某个点的距离为0,距离才是最近的,所以
就是求每个点所在连通块的个数。
找点的时候注意要查找父节点的个数,因为更新的是父节点的值。
#include <stdio.h>
#define LL long long
const int maxn = 100005;
int father[maxn];
int cnt[maxn];
void init ( int n )
{
for ( int i = 1; i <= n; i ++ )
father[i] = i, cnt[i] = 1;
}
int find ( int x )
{
int r = x;
while ( father[r] != r )
r = father[r];
int i = x;
while ( i != r )
{
int j = father[i];
father[i] = r;
i = j;
}
return r;
}
void merge ( int x, int y )
{
int fx = find ( x ), fy = find ( y );
if ( fx != fy )
{
father[fx] = fy;
cnt[fy] += cnt[fx]; //就算赋值也没用,只有父节点会实时更新
}
}
int main ( )
{
int T, n, u, v, w;
scanf ( "%d", &T );
while ( T -- )
{
scanf ( "%d", &n );
init ( n );
for ( int i = 0; i < n-1; i ++ )
{
scanf ( "%d%d%d", &u, &v, &w );
if ( w == 0 ) //权值为0就合并
merge ( u, v );
}
int ans = 0;
for ( int i = 1; i <= n; i ++ )
ans ^= cnt[ find ( i ) ]; //连通块大小
printf ( "%I64d\n", ans );
}
return 0;
}