题意:给定一棵树,树上任意两点的距离为其路径上的边权的异或值,求距离等于某个值的点的对数。
思路:这道题关键是要利用异或的性质。异或最基本的一个性质是和同一个数异或两次不发生改变。而对于这道题来说求出任意两点间的距离是不现实的,但是利用异或的性质,如果我们有了每个点到根的距离,就能间接得到任意两点间的距离,对于任意两点u和v,他们之间的距离就是他们到根的距离异或起来。因为不在u到v路径上的那些边权(即lca(u,v)到根的路径上的边)被异或了两次等于没算,想到这一点就好做了,我们只要借助hash来统计答案即可,注意为查询为0的情况。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 typedef long long ll; 8 const int N = 200001; 9 int mp[N]; 10 int head[N]; 11 int n, e; 12 13 void init() 14 { 15 e = 0; 16 memset( head, -1, sizeof(head) ); 17 memset( mp, 0, sizeof(mp) ); 18 } 19 20 struct Edge 21 { 22 int v, next, w; 23 } edge[N]; 24 25 void addEdge( int u, int v, int w ) 26 { 27 edge[e].v = v; 28 edge[e].w = w; 29 edge[e].next = head[u]; 30 head[u] = e++; 31 } 32 33 void dfs( int u, int fa, int val ) 34 { 35 mp[val]++; 36 for ( int i = head[u]; i != -1; i = edge[i].next ) 37 { 38 int v = edge[i].v, w = edge[i].w; 39 if ( v == fa ) continue; 40 dfs( v, u, val ^ w ); 41 } 42 } 43 44 int main () 45 { 46 int t; 47 scanf("%d", &t); 48 while ( t-- ) 49 { 50 scanf("%d", &n); 51 init(); 52 for ( int i = 1; i < n; i++ ) 53 { 54 int u, v, w; 55 scanf("%d%d%d", &u, &v, &w); 56 addEdge( u, v, w ); 57 addEdge( v, u, w ); 58 } 59 dfs( 1, -1, 0 ); 60 int q; 61 scanf("%d", &q); 62 while ( q-- ) 63 { 64 int tt; 65 scanf("%d", &tt); 66 ll ans = 0; 67 if ( tt == 0 ) 68 { 69 for ( int i = 0; i < N; i++ ) 70 { 71 ans += ( ll ) mp[i] * ( mp[i] + 1 ) / 2; 72 } 73 } 74 else 75 { 76 for ( int i = 0; i < N; i++ ) 77 { 78 int tmp = tt ^ i; 79 if ( tmp >= N ) continue; 80 ans += ( ll ) mp[i] * mp[tmp]; 81 } 82 ans = ans >> 1; 83 } 84 printf("%I64d ", ans); 85 } 86 } 87 return 0; 88 }