1 条题解
-
0
下面记 ,。
考虑 和 怎么走最优。
下面说的平局为 不能再走一步的同时, 也不能再走了。
当 走一步时,能压缩 所能走的空间,这是优的,顺着想下去就能发现当 和 相邻时,双方都只能走自己子树内的节点,所以 和 会以简单路径的方式靠近对方,当不会出现平局且两节点相邻,其中一定有一个点的子树大小超过 时,那么这个点就赢了。想到树的重心的性质,删掉重心后,连通块的大小大于 。这里需要讨论树的重心的个数。 ::::info[有一个时] 以这个点为根,记 为 节点的深度,一个 所能产生的贡献就是 ,这个用树状数组维护。 :::: ::::info[有两个时] 在只有一个树的重心所能产生的贡献是误加上的,当 和 不属于同一个重心且到各自的重心距离相同时会产生平局,所以需要把这种情况减掉。 ::::
#include<bits/stdc++.h> const int MAXN = 500000 + 5; #define pb push_back typedef long long LL; int n, sa, sb, q, a[MAXN], b[MAXN]; std::vector<int> e[MAXN]; inline void add(int u, int v) { e[u].pb(v); } int rt[3], ps, sz[MAXN]; inline void dfs(int u, int fa) { sz[u] = 1; bool fl = 1; for(int v : e[u]) { if(!(v ^ fa)) continue; dfs(v, u); sz[u] += sz[v]; if(sz[v] > n / 2) fl = 0; } if(n - sz[u] > n / 2) fl = 0; if(fl) rt[++ps] = u; } int depth[MAXN]; inline void dfs1(int u, int fa) { depth[u] = depth[fa] + 1; for(int v : e[u]) { if(!(v ^ fa)) continue; dfs1(v, u); } } int id[MAXN]; inline void dfs2(int u, int fa, int op) { id[u] = op, depth[u] = depth[fa] + 1; for(int v : e[u]) { if(!(v ^ fa)) continue; dfs2(v, u, op); } } struct BitTree { int c[MAXN]; inline int lowbit(int x) { return x & -x; } inline void update(int x, int k) { for(int i = x; i <= n; i += lowbit(i)) c[i] += k; } inline int getsum(int x) { int ans = 0; for(int i = x; i >= 1; i -= lowbit(i)) ans += c[i]; return ans; } inline int query(int l, int r) { return getsum(r) - getsum(l - 1); } }T[2]; bool vis[2][MAXN]; int cnt[2][2][MAXN]; int main() { scanf("%d", &n); for(int _ = 1, u, v; _ < n; _++) { scanf("%d%d", &u, &v); add(u, v), add(v, u); } scanf("%d%d%d", &sa, &sb, &q); for(int i = 1; i <= sa; i++) scanf("%d", &a[i]); for(int i = 1; i <= sb; i++) scanf("%d", &b[i]); dfs(1, 0); if(ps == 1) { dfs1(rt[1], 0); for(int i = 1; i <= sa; i++) vis[0][a[i]] = 1, T[0].update(depth[a[i]], 1); for(int i = 1; i <= sb; i++) vis[1][b[i]] = 1, T[1].update(depth[b[i]], 1); LL ans = 0; for(int i = 1; i <= sa; i++) ans += T[1].query(depth[a[i]], n) - vis[1][a[i]]; printf("%lld\n", ans); char z, t; for(int _ = 1, w; _ <= q; _++) { std::cin >> z >> t; scanf("%d", &w); if(z == 'A') { if(t == '+') vis[0][w] = 1, T[0].update(depth[w], 1), ans += T[1].query(depth[w], n) - vis[1][w]; else vis[0][w] = 0, T[0].update(depth[w], -1), ans -= T[1].query(depth[w], n) - vis[1][w]; } else { if(t == '+') vis[1][w] = 1, T[1].update(depth[w], 1), ans += T[0].query(1, depth[w]) - vis[0][w]; else vis[1][w] = 0, T[1].update(depth[w], -1), ans -= T[0].query(1, depth[w]) - vis[0][w]; } printf("%lld\n", ans); } } else { dfs2(rt[1], rt[2], 0); depth[rt[1]] = 0; dfs2(rt[2], rt[1], 1); depth[rt[1]] = 1; for(int i = 1; i <= sa; i++) cnt[0][id[a[i]]][depth[a[i]]]++, vis[0][a[i]] = 1, T[0].update(depth[a[i]], 1); for(int i = 1; i <= sb; i++) cnt[1][id[b[i]]][depth[b[i]]]++, vis[1][b[i]] = 1, T[1].update(depth[b[i]], 1); LL ans = 0; for(int i = 1; i <= sa; i++) ans += T[1].query(depth[a[i]], n) - vis[1][a[i]] - cnt[1][!id[a[i]]][depth[a[i]]]; printf("%lld\n", ans); char z, t; for(int _ = 1, w; _ <= q; _++) { std::cin >> z >> t; scanf("%d", &w); if(z == 'A') { if(t == '+') cnt[0][id[w]][depth[w]]++, vis[0][w] = 1, T[0].update(depth[w], 1), ans += T[1].query(depth[w], n) - vis[1][w] - cnt[1][!id[w]][depth[w]]; else cnt[0][id[w]][depth[w]]--, vis[0][w] = 0, T[0].update(depth[w], -1), ans -= T[1].query(depth[w], n) - vis[1][w] - cnt[1][!id[w]][depth[w]]; } else { if(t == '+') cnt[1][id[w]][depth[w]]++, vis[1][w] = 1, T[1].update(depth[w], 1), ans += T[0].query(1, depth[w]) - vis[0][w] - cnt[0][!id[w]][depth[w]]; else cnt[1][id[w]][depth[w]]--, vis[1][w] = 0, T[1].update(depth[w], -1), ans -= T[0].query(1, depth[w]) - vis[0][w] - cnt[0][!id[w]][depth[w]]; } printf("%lld\n", ans); } } return 0; }
- 1
信息
- ID
- 3402
- 时间
- 6000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者