https://acm.sdut.edu.cn/onlinejudge3/contests/4131/problems/P
可以先通过一次dfs去计算所有的点到节点1的路径异或和,同时记录一下1到其他点是否有符合k的数量。然后我们通过遍历每个异或和,计算他出现的次数乘他与k异或后的值出现的次数,然后把乘积都加起来就是除了根节点以外从u到v的异或和为k的数量,因为这个u,v是不分大小的,而题目分大小,因此将这个和除以2,最后再加上一开始统计的1到其他点是否有符合k的数量就是答案。
再解释一下“计算他出现的次数乘他与k异或后的值出现的次数”这种话,d数组是节点1到其他点的异或和
因此我们可以直接让当前值与k异或直接得到d[v] 。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define pb push_back
using namespace std;
typedef pair<int, int>PII;
int n, m, k,cnt;
map<int, int>mp;
const int N=2e5+10;
vector<PII>g[N];
int d[N];
vector<int>a;
void dfs(int u,int fa){//求出每个点到根节点的异或和
for(auto [v,w]:g[u]){
if(fa==v)continue;
d[v]=d[u]^w;
if(d[v]==k)cnt++;//如果等于k直接加1
if(mp[d[v]]==0)a.pb(d[v]);//记录出现过的异或和
mp[d[v]]++;//记录出现过的异或和数量
dfs(v,u);
}
}
void solve () {
cin>>n>>k;
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
g[u].pb({v,w});
g[v].pb({u,w});
}
dfs(1,-1);
int res=0;
for(auto v:a){
int c=k^v;
if(mp[c])
res+=mp[v]*mp[c];
}
cout<<res/2+cnt;
}
signed main () {
int T = 1;
std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
//cin>>T;
while (T --) solve ();
return 0;
}