题目链接:https://nanti.jisuanke.com/t/39277
题意:
题解:就是看对于一对(u,v),满足路径上权值异或和为0,是多少路径的子集,然后队友所有加和
题解:首先对于我们先处理出从根节点异或下来的值,若(u,v)得到的结果一样,那么u到v的异或和为0,若u,v某一个是另一个的父辈,那么这一对贡献值即为孩子这一分支节点的数目*父辈除去这一分支几点数目剩余的,否则,贡献值为两个分支节点数目相乘,我是分两次计算的,第一次计算保存的都是每一分支节点的数目,这样对于父子这一条链的是不对的,那么我又计算一次,把父子这样的,减去这一分支加上n-父亲这一分支的数目。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=1e9+7;
struct node{
int to,nex;
ll d;
}e[N*2];
int head[N],len;
int n;
map<ll, ll> mp;
void add(int x,int y,ll z)
{
e[len].to=y;
e[len].d=z;
e[len].nex=head[x];
head[x]=len++;
}
ll son[N],v[N];
void dfs1(int u,int fa,ll val)
{
int to;
ll tval;
son[u]=1;
v[u]=val;
for(int i=head[u];i!=-1;i=e[i].nex)
{
to=e[i].to;
if(to==fa) continue;
tval=val^e[i].d;
dfs1(to,u,tval);
son[u]+=son[to];
}
}
ll ans;
void dfs2(int u,int fa)
{
int to;
ans=(ans+son[u]*mp[v[u]]%mod)%mod;
mp[v[u]]=(mp[v[u]]+son[u])%mod;
for(int i=head[u];i!=-1;i=e[i].nex)
{
to=e[i].to;
if(to==fa) continue;
dfs2(to,u);
}
}
void dfs3(int u,int fa)
{
int to;
ans=((ans+son[u]*mp[v[u]]%mod)%mod+mod)%mod;
for(int i=head[u];i!=-1;i=e[i].nex)
{
to=e[i].to;
if(to==fa) continue;
mp[v[u]]=mp[v[u]]-son[to]+n-son[u];
dfs3(to,u);
mp[v[u]]=mp[v[u]]+son[to]-n+son[u];
}
}
int main()
{
int x;
ll y;
scanf("%d",&n);
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=2;i<=n;i++)
{
scanf("%d%lld",&x,&y);
add(x,i,y);
add(i,x,y);
}
dfs1(1,0,0);
dfs2(1,0); // 都保存每一分支的节点数目
mp.clear();
dfs3(1,0); // 处理父子一条链的情况
printf("%lld\n",ans);
return 0;
}
/*
7
1 0
1 1
2 1
2 100
3 200
3 3000000000000
*/