异或前缀和+DFS hdu5416 CRB and Tree

传送门:点击打开链接

题意:给你一棵树,然后Q个问题,每个问题询问有存在多少个f(u,v)等于s其中u<=v,f(u,v)表示节点u到节点v所有边的权值异或和

思路:这道题我觉得出的非常好,运用了位异或的一些妙用。f(u,v)=f(1,u)^f(1,v),因为假设u,v的lca是p,那么1~p这些节点都是公用的,这部分被异或了两次,就抵消了

然后对于Q次问题,假设某一次问题是s,则有s=f(u,v)=f(1,u)^f(1,v)。那么有f(1,v)=s^f(1,u),也就是说,如果我们DFS到节点u,算出了f(1,v),那么对于某一个s,我们就需要算出f(1,v)等于多少,然后再通过cnt数组知道f(1,v)有多少个,把这个值累加到s这个查询的答案中去,就这样DFS遍历完整个树,答案就离线处理完了。复杂度O(Q*N)

trick:当出现下面这种数据的时候

1
10
1 2 0
2 3 0
3 4 0
4 5 0
5 6 0
6 7 0
7 8 0
8 9 0
1
0

可以看出来,答案会等于n(n-1)/2,因为n最大是1e5,所以结果可能会爆int,要用long long保存

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 2e5 + 5;
const int INF = 0x3f3f3f3f;

int Head[MX], Next[MX], rear;
struct Edge {
    int u, v, cost;
} E[MX];
void edge_init() {
    rear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int cost) {
    E[rear].u = u;
    E[rear].v = v;
    E[rear].cost = cost;
    Next[rear] = Head[u];
    Head[u] = rear++;
}

LL ans[MX];
int cnt[MX], Q[MX], Qt;
void DFS(int u, int f, int s) {
    cnt[s]++;
    for(int j = 1; j <= Qt; j++) {
        ans[j] += cnt[s ^ Q[j]];
    }

    for(int i = Head[u]; ~i; i = Next[i]) {
        int v = E[i].v;
        if(f == v) continue;

        DFS(v, u, s ^ E[i].cost);
    }
}

int main() {
    int T, n;//FIN;
    scanf("%d", &T);
    while(T--) {
        edge_init();
        memset(cnt, 0, sizeof(cnt));
        memset(ans, 0, sizeof(ans));

        scanf("%d", &n);
        for(int i = 1; i <= n - 1; i++) {
            int u, v, cost;
            scanf("%d%d%d", &u, &v, &cost);
            edge_add(u, v, cost);
            edge_add(v, u, cost);
        }

        scanf("%d", &Qt);
        for(int i = 1; i <= Qt; i++) {
            scanf("%d", &Q[i]);
        }

        DFS(1, -1, 0);
        for(int i = 1; i <= Qt; i++) {
            printf("%I64d\n", ans[i]);
        }
    }
    return 0;
}


你可能感兴趣的:(异或前缀和+DFS hdu5416 CRB and Tree)