题目链接:https://loj.ac/problem/2236
做法
其实没有什么好说的,这个题就属于那种看起来没什么细节,实际也没有什么细节的题,但是却把我埋了,关于这道题的细节请读者自悟
然后就是树上差分,适用于多次操作一次查询的题
把路径$(u, v)$的边权加$val$的操作:
- $diff[u] += val$, $diff[v] += val$
- $diff[lca(u, v)] -= val$, $diff[fa[lca(u, v)]] -= val$
完
#include <iostream> #include <cstdio> #define Re register using namespace std; inline int read() { int x = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); return x; } const int maxN = 300005; int N, diff[maxN], ord[maxN], num[maxN]; struct Edge { int nxt, to; } e[maxN << 1]; int cnte = 1, head[maxN]; inline void add_Edge(int i, int j) { e[++cnte].nxt = head[i], e[cnte].to = j, head[i] = cnte; } int dep[maxN], anc[maxN][21]; void dfslca(int u, int fa) { dep[u] = dep[fa] + 1; anc[u][0] = fa; for (int i = head[u]; i; i = e[i].nxt) { if (e[i].to == fa) continue; dfslca(e[i].to, u); } } inline int LCA(int x, int y) { if (dep[x] < dep[y]) x ^= y ^= x ^= y; for (int i = 18; i >= 0; --i) if (dep[anc[x][i]] >= dep[y]) x = anc[x][i]; if (x == y) return x; for (int i = 18; i >= 0; --i) if (anc[x][i] != anc[y][i]) x = anc[x][i], y = anc[y][i]; return anc[x][0]; } void dfs(int u, int fa) { for (Re int v, i = head[u]; i; i = e[i].nxt) { if ((v = e[i].to) == fa) continue; dfs(v, u); diff[u] += diff[v]; } } int main() { N = read(); for (Re int i = 1; i <= N; ++i) ord[i] = read(), num[ord[i]] = i; for (Re int i = 1, u, v; i < N; ++i) { u = read(), v = read(); add_Edge(u, v), add_Edge(v, u); } dfslca(1, 0); for (int i = 1; i <= 18; ++i) for (int u = 1; u <= N; ++u) anc[u][i] = anc[anc[u][i - 1]][i - 1]; for (Re int i = 1; i < N; ++i) { Re int x = ord[i], y = ord[i + 1]; Re int lca = LCA(x, y); diff[anc[lca][0]] -= 1, diff[lca] -= 1; diff[x] += 1, diff[y] += 1; } dfs(1, 0); for (int i = 1; i <= N; ++i) printf("%d\n", (num[i] == 1) ? diff[i] : (diff[i] - 1)); return 0; }
原文地址:https://www.cnblogs.com/blog-fgy/p/12363101.html
时间: 2024-11-08 13:18:40