bzoj3757 苹果树
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3757
【RE提示】本题不支持提交了,具体可以见discuss,可以通过discuss的方法来做。
【题解】
树上莫队,就是把in/out的DFS序记录下来,每次查找要么查in[a]...in[b],要么查out[a]...in[b],加上LCA.
然后就正常莫队啦!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# include <math.h> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 4e5 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, m, c[M]; int head[M], nxt[M], to[M], tot = 0; inline void add(int u, int v) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; } inline void adde(int u, int v) { add(u, v), add(v, u); } int fa[M][18], dep[M]; int beg[M], end[M], DFN = 0, dfn[M]; inline void dfs(int x, int fat=0) { beg[x] = ++DFN; dfn[DFN] = x; fa[x][0] = fat; dep[x] = dep[fat] + 1; for (int i=1; i<=17; ++i) fa[x][i] = fa[fa[x][i-1]][i-1]; for (int i=head[x]; i; i=nxt[i]) if(to[i] != fat) dfs(to[i], x); end[x] = ++DFN; dfn[DFN] = x; } inline int lca(int u, int v) { if(dep[u] < dep[v]) swap(u, v); for (int i=17; ~i; --i) if((dep[u]-dep[v]) & (1<<i)) u = fa[u][i]; if(u == v) return u; for (int i=17; ~i; --i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0]; } int bl[M], BLOCK; struct pa { int u, v, a, b, p, id; pa() {} pa(int u, int v, int a, int b, int p, int id) : u(u), v(v), a(a), b(b), p(p), id(id) {} friend bool operator < (pa a, pa b) { return bl[a.u] < bl[b.u] || (bl[a.u] == bl[b.u] && bl[a.v] < bl[b.v]); } }p[M]; int ans[M]; int t[M], s[M], cnt; inline void doit(int x) { t[x] ++; if(t[x] == 1) { ++s[c[x]]; if(s[c[x]] == 1) ++cnt; } else { --s[c[x]]; if(s[c[x]] == 0) --cnt; } if(t[x] == 2) t[x] = 0; } int main() { cin >> n >> m; for (int i=1; i<=n; ++i) scanf("%d", &c[i]); for (int i=1, u, v; i<=n; ++i) { scanf("%d%d", &u, &v); if(u && v) adde(u, v); } dfs(1); BLOCK = sqrt(n); for (int i=1; i<=DFN; ++i) bl[i] = (i-1)/BLOCK+1; for (int i=1, u, v, a, b; i<=m; ++i) { scanf("%d%d%d%d", &u, &v, &a, &b); int LCA = lca(u, v); if(beg[u] > beg[v]) swap(u, v); if(LCA == u) p[i] = pa(beg[u], beg[v], a, b, 0, i); else p[i] = pa(end[u], beg[v], a, b, LCA, i); } sort(p+1, p+m+1); int L = 1, R = 0; for (int i=1; i<=m; ++i) { while(R < p[i].v) ++R, doit(dfn[R]); while(R > p[i].v) doit(dfn[R]), --R; while(L > p[i].u) --L, doit(dfn[L]); while(L < p[i].u) doit(dfn[L]), ++L; if(p[i].p) doit(p[i].p); if(p[i].a == p[i].b) ans[p[i].id] = cnt; else { if(s[p[i].a] && s[p[i].b]) ans[p[i].id] = cnt-1; else ans[p[i].id] = cnt; } if(p[i].p) doit(p[i].p); } for (int i=1; i<=m; ++i) printf("%d\n", ans[i]); return 0; }