题意:
在一棵树上有n个点,n-1条边,每条边都有一个权值。
令f(u,v)等于u到v这条路径上的前缀和。
现在给你Q次询问(Q<=10)
询问f(u,v)=s的路径有多少条。
解析:
由于Q比较小可以直接利用O(n)复杂度的算法来做。
先用sum[u]保存下,从根节点到u的异或和是多少。
用一个hash map来保存,sum[u]出现了多少次。
每次就查询hash map中s ^ sum[u]出现了多少次。
查询的总和除以2就是最终结果。
注意:
如果s=0时,f(u,u)也满足条件,所以还要再加上n。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = (int)2e5 + 10;
struct Edge {
int u, v, val;
Edge() {}
Edge(int u, int v, int val) : u(u), v(v), val(val) {}
};
int mp[maxn], sum[maxn];
vector<Edge> G[maxn];
int n, q;
void init() {
memset(mp, 0, sizeof(mp));
for(int i = 1; i <= n; i++) {
G[i].clear();
}
}
void addEdge(int u, int v, int val) {
G[u].pb(Edge(u, v, val));
}
void dfs(int u, int pre, int val) {
sum[u] = val;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if(pre == v) continue;
dfs(v, u, val^G[u][i].val);
}
}
ll cal(int s) {
ll ret = 0;
for(int i = 1; i <= n; i++) {
ret += mp[s^sum[i]];
}
if(s == 0) ret += n;
return ret / 2;
}
int main() {
int T;
scanf("%d", &T);
int u, v, val, s;
while(T--) {
scanf("%d", &n);
init();
for(int i = 1; i < n; i++) {
scanf("%d%d%d", &u, &v, &val);
addEdge(u, v, val);
addEdge(v, u, val);
}
dfs(1, -1, 0);
for(int i = 1; i <= n; i++) {
mp[sum[i]]++;
}
scanf("%d", &q);
while(q--) {
scanf("%d", &s);
printf("%lld\n", cal(s));
}
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-05 11:41:45