传送门

思路:

如果要求异或为0的路径的个数,这就是一个***题。但是他要求的集合的个数。可以从刚才那个问题扩展开来,问有多少条路径的子路径的异或值为0。这是一个计数的问题,我们知道异或有一个性质 x^x=0
1为树的根节点,xor[i] 表示i到根节点路径上的的异或值
我们可以发现当两个点(s,e)不在一条链上时,ans 应该加上 size[s]*size[e]
如果两个点在一条链上的时候( depth[e] > depth[s] ),令 f 为 s 的儿子节点,并且 f 是 e 的祖先。答案应该 加上 size[e] *(n- size[f] )
异或值很大,我们可以用 unordered_map 来记录,分两种情况来计算答案。

代码:

///#include<bits/stdc++.h>
#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>

#define MT(a, b) memset(a,b,sizeof(a)
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long ll;
const double pai = acos(-1.0);
const double E = 2.718281828459;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const double esp = 1e-6;
const int maxn = 1e5 + 5;

unordered_map<ll, ll>mp;
ll n,sz[maxn], Xor[maxn], ans;
struct node {
    int e;
    ll c;
    int p;
} load[maxn << 1];
int head[maxn], sign;
void add_edge(int s, int e, ll c) {
    load[++sign] = node{e, c, head[s]};
    head[s] = sign;
}
void dfs_size(int s, int pre) {
    sz[s] = 1;
    for(int i = head[s], e; ~i; i = load[i].p) {
        e = load[i].e;
        if(e != pre) {
            Xor[e] = Xor[s] ^ load[i].c;
            dfs_size(e, s);
            sz[s] = (sz[s] + sz[e]) % mod;
        }
    }
}

void dfs_fork(int s, int pre) {     ///求不同链
    ans = (ans + sz[s] * mp[Xor[s]]) % mod;  ///加上当前对答案的贡献
    for(int i = head[s]; ~i; i = load[i].p)
        if(load[i].e != pre)
            dfs_fork(load[i].e, s);
    mp[Xor[s]] = (mp[Xor[s]] + sz[s]) % mod;  /// 递归完子树后
}

void dfs_line(int s, int pre) {     ///求相同链
    ans = (ans + mp[Xor[s]] * sz[s]) % mod;  ///加上当前对答案的贡献
    for(int i = head[s], e; ~i; i = load[i].p) {
        e = load[i].e;
        if(e != pre) {
            mp[Xor[s]] += (n - sz[e]);     ///加上对答案有贡献的节点数量
            dfs_line(e, s);
            mp[Xor[s]] -= (n - sz[e]);     ///递归结束后,减去数量,防止重复计算
        }
    }
}
void init() {
    sign = 0;
    memset(head, -1, sizeof(head));
}
int main() {
    init();
    ll c;
    int  fa;
    scanf("%d", &n);
    for(int i = 2; i <= n; i++) {
        scanf("%d %lld", &fa, &c);
        add_edge(fa, i, c);
    }
    dfs_size(1, -1);
    mp.clear(), dfs_fork(1, -1);
    mp.clear(), dfs_line(1, -1);
    printf("%lld\n", ans);
    return 0;
}