voidmodify(int& u, int x, int k, int L, int R){ if (!u) u = ++segidx; if (L == R) return cnt[u] += k, id[u] = L, void(); if (x <= Mid) modify(ls[u], x, k, L, Mid); elsemodify(rs[u], x, k, Mid+1, R); pushup(u); }
intmerge(int a, int b, int L, int R){ if (!a || !b) return a+b; if (L == R) return cnt[a] += cnt[b], a; ls[a] = merge(ls[a], ls[b], L, Mid); rs[a] = merge(rs[a], rs[b], Mid+1, R); pushup(a); return a; }
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs(int u, int f){ fa[u][0] = f, dep[u] = dep[f] + 1; for (int k = 1; k < K; k++) fa[u][k] = fa[fa[u][k-1]][k-1]; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dfs(to, u); } }
intlca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); for (int k = K-1; k >= 0; k--) if (dep[fa[a][k]] >= dep[b]) a = fa[a][k]; if (a == b) return a; for (int k = K-1; k >= 0; k--) if (fa[a][k] != fa[b][k]) a = fa[a][k], b = fa[b][k]; return fa[a][0]; }
voidcalc(int u, int f){ for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; calc(to, u); rt[u] = merge(rt[u], rt[to], 1, 1e5); } ans[u] = cnt[rt[u]] ? id[rt[u]] : 0; }
intmain(){ cin >> n >> m; for (int i = 1, a, b; i < n; i++) { cin >> a >> b; add(a, b), add(b, a); } dfs(1, 0); for (int i = 1, a, b, c; i <= m; i++) { cin >> a >> b >> c; int u = lca(a, b); modify(rt[a], c, 1, 1, 1e5); modify(rt[b], c, 1, 1, 1e5); modify(rt[u], c, -1, 1, 1e5); modify(rt[fa[u][0]], c, -1, 1, 1e5); } calc(1, 0); for (int i = 1; i <= n; i++) cout << ans[i] << '\n';
return0; }
[NOIP2016] 天天爱跑步
小 C 同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一棵包含 n 个结点和 n−1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从 1 到 n 的连续正整数。
现在有 m 个玩家,第 i 个玩家的起点为 si,终点为 ti。每天打卡任务开始时,所有玩家在第 0 秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)
小 C 想知道游戏的活跃度,所以在每个结点上都放置了一个观察员。在结点 j 的观察员会选择在第 wj 秒观察玩家,一个玩家能被这个观察员观察到当且仅当该玩家在第 wj 秒也正好到达了结点 j。小 C 想知道每个观察员会观察到多少人?
#define Mid ((L+R) >> 1) constint N = 300010, K = 20;
inlinevoidread(int& t){ t = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) t = t*10 + (ch^48), ch = getchar(); }
structSGT { int ls[N*K*2], rs[N*K*2], sum[N*K*2]; int segidx, rt[N];
intmerge(int a, int b, int L, int R){ if (!a || !b) return a + b; if (L == R) return sum[a] += sum[b], a; ls[a] = merge(ls[a], ls[b], L, Mid); rs[a] = merge(rs[a], rs[b], Mid+1, R); return a; }
voidmodify(int& u, int p, int k, int L, int R){ if (!u) u = ++segidx; if (L == R) return sum[u] += k, void(); if (p <= Mid) modify(ls[u], p, k, L, Mid); elsemodify(rs[u], p, k, Mid+1, R); }
intquery(int u, int p, int L, int R){ if (!u || p < L || p > R) return0; if (L == R) return sum[u]; if (p <= Mid) returnquery(ls[u], p, L, Mid); returnquery(rs[u], p, Mid+1, R); } } T1, T2;
int n, m, h[N], w[N], fa[N][K], dep[N], ans[N], idx = 2; structEdge { int to, nxt; } e[N<<1];
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs(int u, int f){ fa[u][0] = f, dep[u] = dep[f] + 1; for (int k = 1; k < K; k++) fa[u][k] = fa[fa[u][k-1]][k-1]; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dfs(to, u); } }
intlca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); for (int k = K-1; k >= 0; k--) if (dep[fa[a][k]] >= dep[b]) a = fa[a][k]; if (a == b) return a; for (int k = K-1; k >= 0; k--) if (fa[a][k] != fa[b][k]) a = fa[a][k], b = fa[b][k]; return fa[a][0]; }
voidcalc(int u, int f){ for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; calc(to, u); T1.rt[u] = T1.merge(T1.rt[u], T1.rt[to], 1, n); T2.rt[u] = T2.merge(T2.rt[u], T2.rt[to], -n, n); } ans[u] = T1.query(T1.rt[u], w[u]+dep[u], 1, n) + T2.query(T2.rt[u], w[u]-dep[u], -n, n); }
intmain(){ read(n), read(m); for (int i = 1, a, b; i < n; i++) { read(a), read(b); add(a, b), add(b, a); }
dfs(1, 0); for (int i = 1; i <= n; i++) read(w[i]);
for (int i = 1, a, b; i <= m; i++) { read(a), read(b); int u = lca(a, b), len = dep[a] + dep[b] - 2*dep[u];
在合并的过程中,最终一定有左边或者右边某个节点为空,那么假设左边的线段树非空,右边的线段树空,对于结点 u 来说,那么此时的 preR(v−1),sufR(v+1) 值就已经确定了,就是递归的一路走下来所有获得到的 sum 值,所以此时给左边线段树的 u 结点每个数都乘上面推出来的式子,所以是需要懒标记的。
#define int long long #define Mid ((L+R) >> 1) constint N = 300010, LogN = 20, INV = 796898467, P = 998244353; int n, m, fa[N], ch[N][2], w[N], nums[N], D[N];
voidread(int& t){ t = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) t = t*10 + (ch^48), ch = getchar(); }
int rt[N], ls[N*LogN], rs[N*LogN], sum[N*LogN], mul[N*LogN], idx;
voidupdate(int u, int k){ mul[u] = mul[u] * k % P; sum[u] = sum[u] * k % P; }
voidpushdown(int u){ if (mul[u] == 1) return; if (ls[u]) update(ls[u], mul[u]); if (rs[u]) update(rs[u], mul[u]); mul[u] = 1; }
voidinsert(int& u, int p, int L, int R){ if (!u) u = create(); if (L == R) return sum[u] = 1, void(); if (p <= Mid) insert(ls[u], p, L, Mid); elseinsert(rs[u], p, Mid+1, R); pushup(u); }
intmerge(int x, int y, int psx, int rsx, int psy, int rsy, int p, int L, int R){ if (!x && !y) return0; if (x && !y) returnupdate(x, (p*psy + (1-p+P)*rsy) % P), x; if (!x && y) returnupdate(y, (p*psx + (1-p+P)*rsx) % P), y; pushdown(x), pushdown(y);
#define Mid ((L+R) >> 1) constint N = 1000010, K = 24; int rt[N], mx[N*K], mxp[N*K], ls[N*K], rs[N*K], dep[N]; int h[N], ans[N], n, segidx, idx = 2; structEdge { int to, nxt; } e[N<<1];
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
intmerge(int u, int v, int L, int R){ if (!u || !v) return u+v; if (L == R) return mx[u] += mx[v], u; ls[u] = merge(ls[u], ls[v], L, Mid); rs[u] = merge(rs[u], rs[v], Mid+1, R); pushup(u); return u; }
voidinc(int& u, int p, int L, int R){ if (!u) u = ++segidx; if (L == R) return ++mx[u], mxp[u] = p, void(); if (p <= Mid) inc(ls[u], p, L, Mid); elseinc(rs[u], p, Mid+1, R); pushup(u); }
voiddfs(int u, int f){ dep[u] = dep[f] + 1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dfs(to, u); } }
voiddp(int u, int f){ for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dp(to, u); rt[u] = merge(rt[u], rt[to], 1, n); } inc(rt[u], dep[u], 1, n); ans[u] = mxp[rt[u]] - dep[u]; }
intmain(){ scanf("%d", &n); for (int i = 1, a, b; i < n; i++) scanf("%d%d", &a, &b), add(a, b), add(b, a); dfs(1, 0); dp(1, 0); for (int i = 1; i <= n; i++) printf("%d\n", ans[i]); return0; }