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;
}
时间: 2024-08-29 10:46:34

HDU 5416 CRB and Tree的相关文章

Hdu 5416 CRB and Tree (bfs)

题目链接: Hdu 5416 CRB and Tree 题目描述: 给一棵树有n个节点,树上的每条边都有一个权值.f(u,v)代表从u到v路径上所有边权的异或值,问满足f(u,v)==m的(u, v)有多少中情况(u, v有可能相同)? 解题思路: 由于xor的特殊性质.x^x=0,对于求f(u, v) == f(u, 1) ^ f(1, u). 又因为x^y == z可以推出x^z == y,对于f(u, 1) ^ f(1, v) == m可以转化为m ^ f(1, v) == f(u, 1)

HDU 5416——CRB and Tree——————【DFS搜树】

CRB and Tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 967    Accepted Submission(s): 308 Problem Description CRB has a tree, whose vertices are labeled by 1, 2, …, N. They are connected b

HDU 5416 CRB and Tree (技巧)

题意:给一棵n个节点的树(无向边),有q个询问,每个询问有一个值s,问有多少点对(u,v)的xor和为s? 注意:(u,v)和(v,u)只算一次.而且u=v也是合法的. 思路:任意点对之间的路径肯定经过LCA的,但是如果如果知道某个点t到根的路径xor和为e,那么就能够得知 x^e=s中的x应该是多少,那就算有多少点到根的xor和为x即可.e是表示t到根的,所以而x也是其他点到根的路径xor和,两个点他们的LCA到根这段会被算2次,那么xor就为0了. (1)DFS算出每个点到根的路径xor和,

HDU 5416 CRB and Tree dfs

链接 题解链接:http://www.cygmasot.com/index.php/2015/08/20/hdu_5416/ 题意: 给定n个点的树 下面n-1行给出边和边权 下面q个询问 每个询问一个数字s 询问有多少条路径使得路径的边权异或结果 == s 结果%(1e9+7) 询问不超过10组. 思路: 设路径{u,v}的边权异或结果为 f(u,v) 设lca 为u v的最近公共祖先 首先得到一个结论,f(u,v) =f(lca, u) ^ f(lca, v) 因为f(lca, root)

hdu 5416 CRB and Tree(dfs+前缀和)

题意: 在一棵树上有n个点,n-1条边,每条边都有一个权值. 令f(u,v)等于u到v这条路径上的前缀和. 现在给你Q次询问(Q<=10) 询问f(u,v)=s的路径有多少条. 解析: 由于Q比较小可以直接利用O(n)复杂度的算法来做. 先用sum[u]保存下,从根节点到u的异或和是多少. 用一个hash map来保存,sum[u]出现了多少次. 每次就查询hash map中s ^ sum[u]出现了多少次. 查询的总和除以2就是最终结果. 注意: 如果s=0时,f(u,u)也满足条件,所以还要

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

hdu 5378 Leader in Tree Land(dp+逆元)

题目链接:hdu 5378 Leader in Tree Land 问题可以理解成N个节点的树,有K个ministers的概率,最后乘上N!.每个节点为ministers的概率即为1 / son(以该节点为根节点的子树包含的节点个数),同样不为ministers的概率为(son-1)/son.所以没有必要考虑树的结构,直接根句子节点的个数转移dp[i][j] dp[i][j] = dp[i-1][j-1] * 1 / son[u] dp[i][j] = dp[i-1][j] * (son[u]-

HDU 4896 Minimal Spanning Tree(矩阵快速幂)

题意: 给你一幅这样子生成的图,求最小生成树的边权和. 思路:对于i >= 6的点连回去的5条边,打表知907^53 mod 2333333 = 1,所以x的循环节长度为54,所以9个点为一个循环,接下来的9个点连回去的边都是一样的.预处理出5个点的所有连通状态,总共只有52种,然后对于新增加一个点和前面点的连边状态可以处理出所有状态的转移.然后转移矩阵可以处理出来了,快速幂一下就可以了,对于普通的矩阵乘法是sigma( a(i, k) * b(k, j) ) (1<=k<=N), 现在

hdu 4603 Color the Tree 2013多校1-4

这道题细节真的很多 首先可以想到a和b的最优策略一定是沿着a和b在树上的链走,走到某个点停止,然后再依次占领和这个点邻接的边 所以,解决这道题的步骤如下: 预处理阶段: step 1:取任意一个点为根节点,找出父子关系并且对这个树进行dp,求出从某个节点出发往下所包含的所有边的权值总和  复杂度O(n) step 2:从tree dp 的结果中计算对于某个节点,从某条边出发所包含的边的综合,并且对其从大到小进行排序 复杂度O(n*logn) step 3:dfs求出这颗树的欧拉回路,以及每个点的