HDU 5416 CRB and Tree(dfs+邻接表)——多校练习10

CRB and Tree

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
CRB has a tree, whose vertices are labeled by 1, 2, …,  N . They are connected by  N  – 1 edges. Each edge has a weight.
For any two vertices  u  and  v (possibly equal),  f(u,v)  is xor(exclusive-or) sum of weights of all edges on the path from  u  to  v .
CRB’s task is for given  s , to calculate the number of unordered pairs  (u,v)  such that  f(u,v)=s . Can you help him?
 

Input
There are multiple test cases. The first line of input contains an integer  T , indicating the number of test cases. For each test case:
The first line contains an integer  N  denoting the number of vertices.
Each of the next  N  - 1 lines contains three space separated integers  a b  and  c  denoting an edge between  a  and  b , whose weight is  c .
The next line contains an integer  Q  denoting the number of queries.
Each of the next  Q  lines contains a single integer  s .
1 ≤  T  ≤ 25
1 ≤  N  ≤  105
1 ≤  Q  ≤ 10
1 ≤  a b  ≤  N
0 ≤  c s  ≤  105
It is guaranteed that given edges form a tree.

 

Output
For each query, output one line containing the answer.
 

Sample Input
  
  
1 3 1 2 1 2 3 2 3 2 3 4
 

Sample Output
  
  
1 1 0
Hint
For the first query, (2, 3) is the only pair that f(u, v) = 2. For the second query, (1, 3) is the only one. For the third query, there are no pair (u, v) such that f(u, v) = 4.
 

Author
KUT(DPRK)
 

Source
 
/*********************************************************************/

题意:有一棵n个结点(结点记为0~n),n-1条加权边的树,定义f(u,v)为结点u与结点v之间所有边权值的异或值,即若u与v之间有e1,e2,e3,e4,e5这么五条边的话,f(u,v)=e1⊕e2⊕e3⊕e4⊕e5,现给你一个异或值s,问满足f(u,v)=s的无序对(u,v)有多少对。

放上出题人的解题报告:


首先,我们来证明一下f(u,v)=f(1,u)⊕f(1,v)

假设1到u之间有e6,e7,e8三条边,以及之前假设的u到v的五条边

f(u,v)=e1⊕e2⊕e3⊕e4⊕e5=e1⊕e2⊕e3⊕e4⊕e5⊕(e6⊕e6)⊕(e7⊕e7)⊕(e8⊕e8)=(e6e7e8)⊕(e1⊕e2⊕e3⊕e4⊕e5e6e7e8)=f(1,u)⊕f(1,v)

所以我们只需dfs一遍,算出所有的f(1,u)值,存下每个异或值出现的次数

又因为若a⊕b=c,则a⊕c=b,所以由f(u,v)=f(1,u)⊕f(1,v)=s可得f(1,v)=f(1,u)⊕s

对于每次询问,我们只需加上对于每个结点u,f(1,u)⊕s值出现的次数即可

另外,s=0的情况比较特殊,需另外考虑,因为u==v的情况下,f(u,v)=f(u,u)=0

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int inf = 1000000000;
const int mod = 1000000007;
struct node
{
    int to,next,w;
}e[2*N];
int h[N],p,s[N];
__int64 m[2*N];
void add_edge(int u,int v,int w)
{
    e[p].to=v;
    e[p].next=h[u];
    e[p].w=w;
    h[u]=p++;
}
void dfs(int u,int r)
{
    int v;
    for(int i=h[u];i+1;i=e[i].next)
    {
        v=e[i].to;
        if(v==r)
            continue;
        s[v]=s[u]^e[i].w;
        m[s[v]]++;
        dfs(v,u);
    }
}
int main()
{
    int t,n,i,a,b,c,q,x,y;
    __int64 ans,sum;
    scanf("%d",&t);
    while(t--)
    {
        p=0;
        memset(h,-1,sizeof(h));
        memset(m,0,sizeof(m));
        scanf("%d",&n);
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
        s[1]=0;
        dfs(1,-1);//dfs算出所有的f(1,u),并记录每个异或值出现的次数
        scanf("%d",&q);
        while(q--)
        {
            sum=ans=0;
            scanf("%d",&x);
            if(!x)//u==v的情况,即s=0
                ans+=n;
            for(i=2;i<=n;i++)
            {
                if(x==s[i])
                    ans++;
                sum+=m[y=s[i]^x];
                if(y==s[i])
                    sum--;
            }
            printf("%I64d\n",sum/2+ans);
        }
    }
    return 0;
}
菜鸟成长记


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值