5416 CRB and Tree

首先预处理出来所有节点到根节点的异或值,然后对于节点u,v,f(u,v)=f(u,1)^f(v,1)(由于异或的性质)

然后我们可以对于每个询问s,枚举所有的v,对于每一个v查找有几个u,使得s^f(v,1)=f(u,1)

至于查找u的时候,我们可以先预处理出来所有的f(u,1)的取值的个数,就是cnt[f(u,1)],然后直接访问cnt[s^f(v,1)]就成了。

特别注意s=0,u=v时候要特殊处理一下


#pragma warning(disable:4996)
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;

vector<int>g[N], e[N];
int a[N], cnt[N * 10];
bool vis[N];

void init(){
	for (int i = 0; i < N; i++){
		g[i].clear();
		e[i].clear();
	}
	memset(a, 0, sizeof a);
	memset(cnt, 0, sizeof cnt);
	memset(vis, false, sizeof vis);
}

void add(int u, int v, int c){
	g[u].push_back(v);
	e[u].push_back(c);
}

void bfs(int u){
	queue<int>q;
	q.push(u);
	a[u] = 0;
	vis[u] = true;
	while (!q.empty()){
		u = q.front(); q.pop();
		for (int i = 0; i < g[u].size(); i++){
			int v = g[u][i], c = e[u][i];
			if (!vis[v]){
				q.push(v);
				a[v] = a[u] ^ c;
				vis[v] = true;
			}
		}
	}
}

void dfs(int u, int val){
	vis[u] = true;
	a[u] = val;
	for (int i = 0; i < g[u].size(); i++){
		int v = g[u][i], c = e[u][i];
		if (!vis[v]){
			dfs(v, val^c);
		}
	}
}

int main(){
	//freopen("in.txt", "r", stdin);
	int t; scanf("%d", &t);
	while (t--){
		init();
		int n; scanf("%d", &n);
		for (int i = 1; i < n; i++){
			int u, v, c;
			scanf("%d %d %d", &u, &v, &c);
			add(u, v, c);
			add(v, u, c);
		}
		//dfs(1, 0);
		bfs(1);
		for (int i = 1; i <= n; i++)cnt[a[i]]++;
		int q; scanf("%d", &q);
		while (q--){
			int x; scanf("%d", &x);
			long long ans = 0;
			for (int i = 1; i <= n; i++){
				ans = ans + (long long)cnt[a[i] ^ x];
			}
			if (x)ans /= 2;
			if (x == 0){
				ans -= (long long)n;
				ans /= 2;
				ans += (long long)n;
			}
			printf("%lld\n", ans);
		}
	}
	return 0;
}


你可能感兴趣的:(5416 CRB and Tree)