1103 POI2007 大都市meg
树链剖分水过,单点修改,树状数组即可。
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define N 250100 using namespace std; int n, m, nowplace = 0; int p[N] = {0}, next[N], v[N], bnum = 0; int son[N] = {0}, fa[N], w[N], top[N], deep[N] = {0}, num[N]; int t[N] = {0}; int lowbit(int x) { return x & -x; } void dfs_1(int now, int fat) { int k = p[now]; num[now] = 1; int maxson = 0; fa[now] = fat; deep[now] = deep[fat] + 1; while (k) { dfs_1(v[k], now); if (num[v[k]] > maxson) { maxson = num[v[k]]; son[now] = v[k]; } num[now] += num[v[k]]; k = next[k]; } } void dfs_2(int now, int nowtop) { int k = p[now]; w[now] = ++nowplace; top[now] = nowtop; if (son[now]) dfs_2(son[now], nowtop); while (k) { if (v[k] != son[now]) dfs_2(v[k], v[k]); k = next[k]; } } void add(int now, int addnum) { while (now <= n) { t[now] += addnum; now += lowbit(now); } return; } int task(int now) { int ans = 0; while (now) { ans += t[now]; now -= lowbit(now); } return ans; } int ask(int u, int v) { int f1 = top[u], f2 = top[v]; if (deep[f1] < deep[f2]) { swap(f1, f2); swap(u, v); } if (f1 == f2) return task(max(w[u], w[v])) - task(min(w[u], w[v])-1); else { int ans = 0; ans = task(w[u]) - task(w[f1]-1); // 搞清先后 ans += ask(fa[f1], v); return ans; } } int main() { scanf("%d", &n); for (int i = 1; i < n; ++i) { int x, y; scanf("%d%d", &x, &y); if (x > y) swap(x, y); bnum++; next[bnum] = p[x]; p[x] = bnum; v[bnum] = y; } dfs_1(1, 0); dfs_2(1, 1); for (int i = 2; i <= n; ++i) add(w[i], 1); scanf("%d", &m); m = m+n-1; for (int i = 1; i <= m; ++i) { char s[2]; scanf("%s", s); if (s[0] == 'A') { int x, y; scanf("%d%d", &x, &y); if (x > y) swap(x, y); add(w[y], -1); } else { int x; scanf("%d", &x); printf("%d\n", ask(1, x)); } } return 0; }
还有DFS序做法,其实就是求点到根的路径权值和,样例的DFS序 为 1 4 5 5 4 3 3 2 2 1
我们把入序的地方+1 出序的地方-1, 查询的时候求入序的前缀和 - 1 就OK了(因为要减去多出来的1节点)
修改的时候入序和出序都改为0
上代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define N 250010 using namespace std; int n, m, nowplace = 0; int p[N] = {0}, next[N], v[N], bnum = 0; int t[N*2] = {0}; int first[N], second[N]; int lowbit(int x) { return x & -x; } void add(int now, int addnum) { while (now <= 2*n) { t[now] += addnum; now += lowbit(now); } } void dfs(int now) { int k = p[now]; add(++nowplace, 1); first[now] = nowplace; while (k) { dfs(v[k]); k = next[k]; } add(++nowplace, -1); second[now] = nowplace; } int ask(int now) { int ans = 0; while (now) { ans += t[now]; now -= lowbit(now); } return ans; } int main() { scanf("%d", &n); for (int i = 1; i < n; ++i) { int x, y; scanf("%d%d", &x, &y); if (x > y) swap(x, y); bnum++; next[bnum] = p[x]; p[x] = bnum; v[bnum] = y; } dfs(1); scanf("%d", &m); m = m+n-1; for (int i = 1; i <= m; ++i) { char s[2]; scanf("%s", s); if (s[0] == 'A') { int x, y; scanf("%d%d", &x, &y); if (x < y) swap(x, y); add(first[x], -1); add(second[x], 1); } else { int x; scanf("%d", &x); printf("%d\n", ask(first[x])-1); } } return 0; }