异或前缀和+DFS hdu5416 CRB and Tree

来源:互联网 发布:java从键盘赋值 编辑:程序博客网 时间:2024/04/30 04:31

传送门:点击打开链接

题意:给你一棵树,然后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:当出现下面这种数据的时候

1101 2 02 3 03 4 04 5 05 6 06 7 07 8 08 9 010

可以看出来,答案会等于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;}


1 0