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?
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.
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 0HintFor 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)=(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[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;
}
菜鸟成长记