HDU 5416 CRB and Tree

题目大意:
T, T组测试数据
给你一个n有n个点,下标是从 1 开始的。这个是一棵树,然后下面是n-1条边,
每条边的信息是 s,e,w 代表 s-e的权值是w
然后是一个Q代表Q次询问。
每次询问是一个数字a,  代表 所有路径想异或后的值是 a的路径有多少条。
(注:  自己到自己的异或值是0,若a是0要考虑自己到自己)
 
题目分析:
从根节点开始进行一遍DFS求出所有点到 跟节点的异或值。也就得出来了根节点到达其他任何一个点的异或值。
比如 a 是跟节点到A的异或值, b是根节点到B的异或值
那么A->B的路径上的异或值就是  a^b.然后把所有的异或值桶排一下。
注意一点 a^b 的值是可能大于10W的,最大是260000多
 
 
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
#define INF 0x3fffffff
typedef long long LL;
const LL  maxn = 300005;
const LL  mod  = 1e9+7;

bool vis[maxn];
int k, Head[maxn], n, Max = 0;
LL num[maxn];
struct node
{
    int e, next, w;
}Edge[maxn*2];

void AddEdge(int s,int e,int w)
{
    Edge[k].w = w;
    Edge[k].e = e;
    Edge[k].next = Head[s];
    Head[s] = k;
    k ++;
}

void DFS(int root,int a)
{
    vis[root] = true;
    num[a] ++;
    for(int i=Head[root]; i!=-1; i=Edge[i].next)
    {
        int e = Edge[i].e;
        if(vis[e] == true)
            continue;
        DFS(e, a^Edge[i].w);
    }
}

int main()
{

    int Q, T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        k = 0;
        memset(Head, -1, sizeof(Head));
        memset(vis, false, sizeof(vis));
        memset(num, 0, sizeof(num));
        for(int i=0; i<n-1; i++)
        {
            int s, e, w;
            scanf("%d %d %d",&s, &e, &w);
            AddEdge(s, e, w);
            AddEdge(e, s, w);
        }
        DFS(1, 0);

        scanf("%d", &Q);
        while( Q --)
        {
            int a;
            LL ans = 0;
            scanf("%d", &a);
            if(a == 0)
                ans += n;
            for(int i=0; i<=270000; i++)
            {
                if(a == 0)
                    ans += num[i]*(num[i]-1)/2;
                else if(i < (a^i) && num[i] && num[a^i])
                    ans += num[i]*num[a^i];
            }
            printf("%lld\n", ans);
        }
    }
    return 0;
}


 

posted @ 2015-08-21 09:41  向前走丶不回首  阅读(167)  评论(0编辑  收藏  举报