Description
给你具有n个结点n−1条边的无向无环连通图,结点编号1∼n,每条边上有一个数作为他的边权,定义函数f(i,j)为连接i,j的简单路径的所有边权的异或值
求
,⊕为按位异或运算,
表示l∼r所有整数异或后的结果
Input
输入的第一行为一个整数T,代表测试用例的组数
接下来的T组测试用例按照如下格式给出:
每组数据占n行,第一行有1个整数n,接下来的n−1行,每行有3个整数u,v,w,分别表示每条边的起点、终点、权值
Output
对于每组测试数据,在新的一行中输出答案
数据范围
1≤T≤1000
1≤n≤2⋅10^5
∑n≤2⋅10^5
1≤u,v≤n
0≤w≤10^6
样例输入
2
1
2
1 2 3
样例输出
0
3
题目大意:
求树中所有结点两两组合的函数值的异或和,其中,函数f(i,j)为连接i,j的简单路径的所有边权的异或值。
分析:
考虑每条边权在总的答案中的贡献。
对于一条边 (u,v) ,边权为 w ,由于树的性质,则所有在 u 一侧的点要到达在 v 一侧的点都必须经过这条边,假设在 u 一侧的点(包括 u )有 sz[u] 个,在 v 一侧的点(包括 v)有 sz[v] 个,则这条边在答案中计算了 sz[u] * sz[v] 次。
由于异或的性质,如果 sz[u] * sz[v] 为偶数,则这条边对答案的贡献为0;如果 sz[u] * sz[v] 为奇数,则这条边对答案的贡献为w。
具体解释见代码。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define mst(a,num) memset(a,num,sizeof a)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef vector<int> VI;
const ll mod = 1e9 + 7;
const int maxn = 200000 + 5;
struct node
{
int v,w;
};
vector<node> edge[maxn];
int ans=0;
int sz[maxn];
int n;
void dfs(int x,int fa){
sz[x]=1;
for(auto &nod:edge[x]){
if(nod.v==fa) continue;
dfs(nod.v,x);
sz[x]+=sz[nod.v];
int f1=(sz[nod.v]&1),f2=((n-sz[nod.v])&1);
if(f1==1&&f2==1){
ans^=nod.w;
}
}
}
int main() {
int t;
scanf("%d",&t);
while(t--){
int u,v,w;
scanf("%d",&n);
rep(i,1,n) edge[i].clear();
node tmp;
rep(i,1,n-1){
scanf("%d%d%d",&u,&v,&w);
tmp.w=w;
tmp.v=v;
edge[u].push_back(tmp);
tmp.v=u;
edge[v].push_back(tmp);
}
ans=0;
dfs(1,0);
printf("%d\n",ans);
}
return 0;
}