标签:
学习了树上莫队,树分块后对讯问的$dfs序$排序,然后就可以滑动树链处理答案了。
关于树链的滑动,只需要特殊处理一下$LCA$就行了。
在这里一条树链保留下来给后面的链来转移的$now$的为这条树链上所有点除去$LCA$的颜色种数。因为如果要考虑$LCA$情况就太多了,不如单独考虑$LCA$。
转移后加上当前链的$LCA$进行统计,然后再去掉这个$LCA$更新一下$now$值给后面的链转移。
这都是我的理解,说的有点不清楚,具体请看vfk的题解 OTZ 虽然不是这道题,但是通过这篇博客学习树上莫队也是很好的。
PS:压行大法使代码看起来像一堵墙
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define N 50003 #define M 100003 #define read(x) x=getint() using namespace std; inline int getint() {int k = 0, fh = 1; char c = getchar(); for(; c < ‘0‘ || c > ‘9‘; c = getchar()) if (c == ‘-‘) fh = -1; for(; c >= ‘0‘ && c <= ‘9‘; c = getchar()) k = k * 10 + c - ‘0‘; return k * fh;} int n, m, color[N], cnt = 0, fa[N][16], deep[N], dfn[N << 1], now = 0; int belong[N], cntblo = 0, sqrblo, top = 0, sta[N], ans[M], colsum[N], point[N]; short v[N]; struct Enode {int nxt, to;} E[N << 1]; struct node {int x, y, a, b, id;} q[M]; inline bool cmp(node A, node B) {return belong[A.x] == belong[B.x] ? dfn[A.y] < dfn[B.y] : dfn[A.x] < dfn[B.x];} inline void ins(int x, int y) {E[++cnt].nxt = point[x]; E[cnt].to = y; point[x] = cnt;} inline void dfs(int x) { dfn[x] = ++cnt; int mark = top; for(int i = 1; i <= 15; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for(int tmp = point[x]; tmp; tmp = E[tmp].nxt) { int v = E[tmp].to; if (v == fa[x][0]) continue; deep[v] =deep[x] + 1; fa[v][0] = x; dfs(v); if (top - mark >= sqrblo) { ++cntblo; while (top != mark) belong[sta[top--]] = cntblo; } } sta[++top] = x; } inline int LCA(int x, int y) { if (deep[x] < deep[y]) swap(x, y); int k = deep[x] - deep[y]; for(int j = 15; j >= 0; --j) if (k & (1 << j)) x = fa[x][j]; if (x == y) return x; for(int j = 15; j >= 0; --j) if (fa[x][j] != fa[y][j]) x = fa[x][j], y = fa[y][j]; return fa[x][0]; } inline void pushup(int x) { if (v[x]) { --colsum[color[x]]; if (!colsum[color[x]]) --now; } else { if (!colsum[color[x]]) ++now; ++colsum[color[x]]; } v[x] ^= 1; } inline void change(int x, int y) { while (x != y) { if (deep[x] < deep[y]) pushup(y), y = fa[y][0]; else pushup(x), x = fa[x][0]; } //O)Z这个方法好神啊!!!我为什么想不到一个一个往上跳呢QAQ } int main() { read(n); read(m); for(int i = 1; i <= n; ++i) read(color[i]); int u, v; for(int i = 1; i <= n; ++i) { read(u); read(v); if (u == 0 || v == 0) continue; ins(u, v); ins(v, u); } sqrblo = ceil(sqrt(n)); cnt = 0; dfs(1); while (top) belong[sta[top--]] = cntblo; for(int i = 1; i <= m; ++i) { read(q[i].x); read(q[i].y); read(q[i].a); read(q[i].b); q[i].id = i; if (dfn[q[i].x] > dfn[q[i].y]) swap(q[i].x, q[i].y); } sort(q + 1, q + m + 1, cmp); q[0].x = q[0].y = 1; for(int i = 1; i <= m; ++i) { change(q[i - 1].x, q[i].x); change(q[i - 1].y, q[i].y); int lca = LCA(q[i].x, q[i].y); pushup(lca); ans[q[i].id] = now; if (colsum[q[i].a] && colsum[q[i].b] && q[i].a != q[i].b) --ans[q[i].id]; pushup(lca); } for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]); return 0; }
$SDOI2016 Round1$之前做的最后一道题了,希望省选不要爆零啊$QAQ$
【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)
标签:
原文地址:http://www.cnblogs.com/abclzr/p/5365666.html