https://nanti.jisuanke.com/t/39277
上半年湘潭西安全败在树形DP不会,然后浪费大量时间后做另外一题还没做完,菜哭.jpg
这题首先是想到路径的异或为0可以变成点到根的路径异或值相等
然后想到枚举u' <v' 这个相等更方便,接着就是想怎么统计有多少u<v可以选
然后比赛的时候就不会了。。。。头都想烂了,主要是当时已经写了4题了,然后又到了后期,有点慌张,降智buff++,结果放弃这题去写一道原题了,结果那原题最后5分钟过了样例以后也WA了。
其实就按照dfs顺序,当前为异或值a[u]的点之前已经出现过异或值a[u]的点求总方案数就行了,这样不管是谁大谁小都是求了一次,不会造成重复。
那么对如果一个a[u]的祖先节点t也是a[u],那么方案数就是son[u]*(n-那个t到这个点u的儿子的v的son[v]),如果不是,那么就是son[t]*son[u],然后我们用一个map保存所有异或为a[u]的之前的节点要乘的总和及每次都ans+=son[u]*sum[a[u]],然后动态维护sum[a[u]]就行了。
#include<bits/stdc++.h>
#define maxl 200010
using namespace std;
const int mod=1e9+7;
int n,cnt=0;
int ehead[maxl],son[maxl];
long long ans;
long long a[maxl];
map<long long,long long>sum;
struct ed
{
int to,nxt;
}e[maxl];
inline void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void dfs1(int u)
{
int v;son[u]=1;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
dfs1(v);
son[u]+=son[v];
}
}
inline void prework()
{
scanf("%d",&n);
a[1]=0;cnt=0;
int fa;long long w;
for(int i=2;i<=n;i++)
{
scanf("%d%lld",&fa,&w);
add(fa,i);a[i]=a[fa]^w;
}
dfs1(1);
}
inline void add(long long &x,long long y)
{
x=((x+y)%mod+mod)%mod;
}
inline void dfs2(int u)
{
int v;
add(ans,1ll*sum[a[u]]*son[u]%mod);
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
sum[a[u]]=((sum[a[u]]+n-son[v])%mod+mod)%mod;
dfs2(v);
sum[a[u]]=((sum[a[u]]-(n-son[v]))%mod+mod)%mod;
}
sum[a[u]]=(sum[a[u]]+son[u])%mod;
}
inline void mainwork()
{
ans=0;
dfs2(1);
}
inline void print()
{
printf("%lld",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}