您的位置:首页 > 其它

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

2015-08-21 11:12 453 查看


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

2015 Multi-University Training Contest 10

 
/*********************************************************************/

题意:有一棵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)=(e6⊕e7⊕e8)⊕(e1⊕e2⊕e3⊕e4⊕e5⊕e6⊕e7⊕e8)=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
,p,s
;
__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;
}菜鸟成长记
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: