首先容咱吐槽一下,这spoj跟bzoj一个尿性,RE显示成WA,害的咱弄了近一个小时。
题意:一颗树上每个点都有一个权值$v$,求一条路径上权值的种数。
题解:树上莫队。
首先咱dfs一下,记录这棵树的欧拉序$f$(就是进入的时候记录,出去的时候再记录的那种)。这样就把莫队在树上的转移变成了在欧拉序上的转移。
那么如何支持对$u-v$的查询呢?
先想想用欧拉序做一棵有边权树的链上求和怎么做到。
咱记$dis_i$为$i$到根节点的距离,那么$u-v$的答案就是$dis_u+dis_v-2*dis_{lca}$。
这个其实也类似。如果当前转移到的区间是$[l,r]$,其中节点$u$出现$0$或$2$次,咱不算$v_u$,出现$1$次才算。
再来说说查询的节点$u$和$v$在欧拉序上的区间$[l,r]$是怎么得到的。
记$I_i$,$O_i$分别为进入和离开$i$的时间。不妨设$I_u < I_v$。
如果$u=lca(u,v)$,那么区间就是$[I_u, I_v]$($[O_v,O_u]$是一样的)。
如果$u \neq lca(u,v)$,那么区间就是$[O_u, I_v] + [I_{lca},I_{lca}]$。
代码写的很$ugly$,可能会再写一个比较$beautiful$的。
1 #include<cassert> 2 #include<map> 3 #include<cmath> 4 #include<vector> 5 #include<cstdio> 6 #include<iostream> 7 #include<algorithm> 8 #define pb push_back 9 using namespace std; 10 inline char nc() { 11 static char b[1<<14],*s=b,*t=b; 12 return s==t&&(t=(s=b)+fread(b,1,1<<14,stdin),s==t)?-1:*s++; 13 } 14 inline void read(int &x) { 15 char b = nc(); x = 0; 16 for (; !isdigit(b); b = nc()); 17 for (; isdigit(b); b = nc()) x = x * 10 + b - ‘0‘; 18 } 19 const int N = 40010; 20 int n, m, val[N], H; 21 map < int , int > h; 22 vector < int > g[N]; 23 inline int idx(int t) { 24 return h.count(t) ? h[t] : h[t] = ++H; 25 } 26 inline void ae(int u, int v) { 27 g[u].pb(v); g[v].pb(u); 28 } 29 int D, I[N], O[N], f[N*2], S; 30 int fa[N], son[N], dep[N], sz[N], top[N]; 31 void dfs1(int u, int f) { 32 sz[u] = 1; fa[u] = f; dep[u] = dep[f] + 1; 33 for (int i = 0, v; i < g[u].size(); ++i) if ((v = g[u][i]) != f) { 34 dfs1(v, u); sz[u] += sz[v]; 35 if (sz[son[u]] < sz[v]) son[u] = v; 36 } 37 } 38 void dfs2(int u, int tp) { 39 I[u] = ++D; 40 top[u] = tp; if (son[u]) dfs2(son[u], tp); 41 for (int v, i = 0; i < g[u].size(); ++i) 42 if (v = g[u][i], v != fa[u] && v != son[u]) dfs2(v, v); 43 O[u] = ++D; 44 } 45 int findLca(int a, int b) { 46 for (; top[a] != top[b]; a = fa[top[a]]) 47 if (dep[top[a]] < dep[top[b]]) swap(a, b); 48 return dep[a] < dep[b] ? a : b; 49 } 50 struct Node { 51 int l, r, id, e; 52 inline void init(int u, int v, int i) { 53 if (I[u] > I[v]) swap(u, v); 54 int lca = findLca(u, v); 55 if (u == lca) l = I[u], r = I[v], e = 0; 56 else r = O[u], l = I[v], e = lca; 57 if (l > r) swap(l, r); id = i; 58 59 } 60 inline bool operator<(const Node &o) const { 61 return (l / S < o.l / S) || (l / S == o.l / S && r < o.r); 62 } 63 } q[100010]; 64 int cnt[N], tans, oc[N], ans[100010]; 65 inline void add(int x) { 66 if (++cnt[x] == 1) ++tans; 67 } 68 inline void del(int x) { 69 if (--cnt[x] == 0) --tans; 70 } 71 int main() { 72 read(n); read(m); S = sqrt(n * 2); 73 for (int t, i = 1; i <= n; ++i) 74 read(t), val[i] = idx(t); 75 for (int i = 1, u, v; i < n; ++i) 76 read(u), read(v), ae(u, v); 77 dfs1(1, 0); dfs2(1, 1); 78 for (int i = 1; i <= n; ++i) f[I[i]] = f[O[i]] = i; 79 for (int u, v, i = 0; i < m; ++i) 80 read(u), read(v), q[i].init(u, v, i); 81 sort(q, q + m); add(f[1]); ++oc[f[1]]; 82 for (int i = 0, l = 1, r = 1; i < m; ++i) { 83 while (r < q[i].r) { 84 int u = f[++r]; 85 assert(oc[u] != 2); 86 if (oc[u] == 1) del(val[u]); 87 else add(val[u]); 88 ++oc[u]; 89 } 90 while (r > q[i].r) { 91 int u = f[r--]; 92 assert(oc[u] != 0); 93 if (oc[u] == 1) del(val[u]); 94 else add(val[u]); 95 --oc[u]; 96 } 97 while (l < q[i].l) { 98 int u = f[l++]; 99 assert(oc[u] != 0); 100 if (oc[u] == 1) del(val[u]); 101 else add(val[u]); 102 --oc[u]; 103 } 104 while (l > q[i].l) { 105 int u = f[--l]; 106 assert(oc[u] != 2); 107 if (oc[u] == 1) del(val[u]); 108 else add(val[u]); 109 ++oc[u]; 110 } 111 ans[q[i].id] = tans; 112 if (q[i].e && cnt[val[q[i].e]] == 0) ++ans[q[i].id]; 113 /* 114 if (q[i].lca != q[i].u && cnt[val[q[i].lca]] == 0) ++cnt[val[q[i].lca]]; 115 for (int j = 1; j <= H; ++j) printf("%d ", cnt[j]); puts(""); 116 if (q[i].lca != q[i].u && cnt[val[q[i].lca]] == 0) --cnt[val[q[i].lca]]; 117 puts("OC BEGIN"); 118 for (int j = 1; j <= n; ++j) printf("%d ", oc[j]); 119 puts("OC END"); 120 */ 121 } 122 for (int i = 0; i < m; ++i) printf("%d\n", ans[i]); 123 return 0; 124 }