http://codeforces.com/blog/entry/43230树上莫队从这里学的, 受益匪浅..
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include <string> #include <queue> #include <stack> #include <bitset> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<1 #define mem(a) memset(a, 0, sizeof(a)) #define rson m+1, r, rt<<1|1 #define mem1(a) memset(a, -1, sizeof(a)) #define mem2(a) memset(a, 0x3f, sizeof(a)) #define rep(i, n, a) for(int i = a; i<n; i++) #define fi first #define se second typedef pair<int, int> pll; const double PI = acos(-1.0); const double eps = 1e-8; const int mod = 1e9+7; const int inf = 1061109567; const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; const int maxn = 4e4+5; int in[maxn], head[maxn], num, out[maxn], cnt, val[maxn], ans[100005], a[maxn]; int f[maxn], d[maxn], p[maxn][20], n, m, vis[maxn], times[maxn], res, id[maxn*2]; struct node { int to, nextt; }e[maxn*2]; struct query { int l, r, lca, id, block; bool operator < (query a) const { if(block == a.block) return r<a.r; return block<a.block; } }q[100005]; void add(int u, int v) { e[num].to = v, e[num].nextt = head[u], head[u] = num++; } void init() { mem1(head); mem1(p); } void dfs(int u, int fa) { in[u] = ++cnt; id[cnt] = u; f[u] = fa; for(int i = head[u]; ~i; i = e[i].nextt) { int v = e[i].to; if(v == fa) continue; d[v] = d[u]+1; dfs(v, u); } out[u] = ++cnt; id[cnt] = u; } void initLca() { int i, j; for(i = 1; i<=n; i++) { p[i][0] = f[i]; } for(j = 1; (1<<j)<=n; j++) { for(i = 1; i<=n; i++) { if(~p[i][j-1]) p[i][j] = p[p[i][j-1]][j-1]; } } } int lca(int u, int v) { if(d[u]<d[v]) swap(u, v); int i, j; for(i = 0; (1<<i)<=d[u]; i++) ; i--; for(j = i; j>=0; j--) if(d[u]-(1<<j)>=d[v]) u = p[u][j]; if(u == v) return v; for(j = i; j>=0; j--) { if(p[u][j] != -1 && p[u][j] != p[v][j]) { u = p[u][j]; v = p[v][j]; } } return f[u]; } void check(int x) { if(vis[x] && --times[val[x]]==0) { res--; } else if(vis[x]==0 && times[val[x]]++ == 0) { res++; } vis[x]^=1; } void cal() { int L = q[0].l, R = q[0].l-1; for(int i = 0; i<m; i++) { while(L<q[i].l) { check(id[L++]); } while(L>q[i].l) { check(id[--L]); } while(R<q[i].r) { check(id[++R]); } while(R>q[i].r) { check(id[R--]); } if(q[i].lca != id[q[i].l] && q[i].lca != id[q[i].r]) { check(q[i].lca); } ans[q[i].id] = res; if(q[i].lca != id[q[i].l] && q[i].lca != id[q[i].r]) { check(q[i].lca); } } } int main() { int u, v; cin>>n>>m; int BLOCK = sqrt(n); init(); for(int i = 1; i<=n; i++) { scanf("%d", &val[i]); a[i-1] = val[i]; } sort(a, a+n); int N = unique(a, a+n)-a; for(int i = 1; i<=n; i++) { val[i] = lower_bound(a, a+N, val[i])-a+1; } for(int i = 0; i<n-1; i++) { scanf("%d%d", &u, &v); add(u, v); add(v, u); } d[1] = 1; dfs(1, -1); initLca(); for(int i = 0; i<m; i++) { scanf("%d%d", &u, &v); if(in[u]>in[v]) swap(u, v); q[i].lca = lca(u, v); if(q[i].lca == u) { q[i].l = in[u]; q[i].r = in[v]; } else { q[i].l = out[u]; q[i].r = in[v]; } q[i].block = q[i].l/BLOCK; q[i].id = i; } sort(q, q+m); cal(); for(int i = 0; i<m; i++) { printf("%d ", ans[i]); } return 0; }