Loading

HDU-5416 CRB and Tree

CRB and Tree

思维

路径异或一般考虑预处理从根到所有结点的前缀异或和,然后再进行计算:\(f(u, v) = f(1, u) \oplus f(1, v)\)

初始化后将所有值用桶装起来,然后枚举每一个起点 \(u\),然后终点就是 所询问的异或值 \(s\) \(\oplus\) \(f(1, u)\) 后,所有等于这个值的数量

注意 \(0\) 的情况要在答案上加上一个 \(n\) 再除二

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long ll;
#define pii pair<int, int>
vector<pii>gra[maxn];
int sum[maxn], vis[maxn];

void dfs(int now, int pre)
{
    for(pii a : gra[now])
    {
        if(pre == a.first) continue;
        sum[a.first] ^= a.second ^ sum[now];
        dfs(a.first, now);
    }
    vis[sum[now]]++;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        for(int i=0; i<=n; i++) gra[i].clear();
        for(int i=1; i<n; i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            gra[a].push_back({b, c});
            gra[b].push_back({a, c});
        }
        dfs(1, 1);
        int q;
        scanf("%d", &q);
        while(q--)
        {
            int x;
            scanf("%d", &x);
            ll ans = 0;
            for(int i=1; i<=n; i++)
                ans += vis[x ^ sum[i]];
            if(x == 0) ans += n;
            printf("%lld\n", ans / 2);
        }
        for(int i=1; i<=n; i++) {vis[sum[i]] = 0; sum[i] = 0;}
    }
    return 0;
}
posted @ 2022-07-28 22:38  dgsvygd  阅读(17)  评论(0编辑  收藏  举报