树形DP HDU 5416

16 篇文章 0 订阅

CRB and Tree

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2244    Accepted Submission(s): 683


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.
 

题意:有一棵树上有n个点,n - 1 条边,树上每相邻两点之间有一个权值,有 q 次询问,每次询问给出一个值 s ,问有多少个 pair(u,v) 的 值 f(u,v) = s,f(u,v) = 从u 到 v 路径上所有边权的异或值

思路:它是一棵树,树的根为 1,那么 f(1,u) 表示从 根节点一直异或到u,f(1,v)表示从根节点异或到 v

那么 f(1,u) ^ f(1,v) = f(u,v) , 所以只要求出 根节点到所有其他节点的异或值就可以了 记录为 dp[i]

特殊情况是 当 s = 0 的时候 ,pair(u,u) 是满足的,所以 ans += u

然后对于一般情况,从2到n,如果  dp[i] == s,那么 ans ++ ,表示 pair(1,i) 满足

然后就是令 tmp = dp[i] ^ s ,则有 cnt[tmp]种情况是满足的 因为 tmp ^ dp[i] = s,但是这里有重复情况,要除 2

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define mem(a,x) memset(a,x,sizeof(a))
#define ll long long
#define maxn 100005

struct node{
	int v,w;
	node(int v_,int w_) : v(v_),w(w_){}
};
vector<node>vec[maxn];
int cnt[maxn * 2];
ll dp[maxn * 2],sum,ans;

void add(int u,int v,int w){
	vec[u].push_back(node(v,w));
} 
void treedp(int u,int pre){
	int v,w;
	int sz = vec[u].size();
	for(int i = 0;i < sz;i++){
		v = vec[u][i].v;
		w = vec[u][i].w;
		if(v == pre)
			continue;
		dp[v] = dp[u] ^ w;
		cnt[dp[v]]++;
		treedp(v,u);
	}
}
int main(){
	int t,n,q,u,v,w,s,tmp;
	scanf("%d",&t);
	while(t--){
		mem(cnt,0);
		scanf("%d",&n);
		for(int i = 1;i <= n;i++)
			vec[i].clear();
		for(int i = 1;i < n;i++){
			scanf("%d %d %d",&u,&v,&w);
			add(u,v,w);
			add(v,u,w);
		}
		dp[1] = 0;
		treedp(1,-1);
		scanf("%d",&q);
		while(q--){
			sum = ans = 0;
			scanf("%d",&s);
			if(s == 0)
				ans += n;
			for(int i = 2;i <= n;i++){
				if(s == dp[i])
					ans++;
				tmp = dp[i] ^ s;
				sum += cnt[tmp];
				if(tmp == dp[i])
					sum--;
			}
			printf("%lld\n",sum / 2 + ans);
		}
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值