雜湊表 --- 模擬散列表
阿新 • • 發佈:2022-03-09
\(\text{Problem}\)
給你一棵樹,點帶權 \(a_x\),邊帶權,每次詢問給個點 \(x\)
詢問所有 \(y\) 滿足 \(a_y \le a_x\),求 \(\sum dis_{x,y}\)
強制線上
\(n \le 150000,Q \le 200000,A \le 10^9\)
\(\text{Solution}\)
\(ans = dis_x \times n + \sum dis_y - 2 \times \sum dis_{lca_{x,y}}\)
發現問題在第三項
其實這個問題可以仿照 \([GXOI/GZOI]\) 舊詞的解法
但要強制線上
考慮按 \(a\) 排序後可持久化舊詞中的線段樹即可
\(\text{Code}\)
#include <cstdio> #include <algorithm> #include <iostream> #define IN inline using namespace std; typedef long long LL; const int N = 2e5 + 5, SZ = N * 55; int n, q, A, h[N], tot, rt[N], size; LL dis[N], f[N], sd[N]; struct edge{int nxt, to, w;}e[N * 2]; IN void add(int x, int y, int z){e[++tot] = edge{h[x], y, z}, h[x] = tot;} struct node{int id, v;}a[N]; IN bool cmp(node a, node b){return a.v < b.v ? 1 : (a.v == b.v ? a.id < b.id : 0);} int top[N], fa[N], dfn[N], rev[N], siz[N], son[N], dfc; void dfs1(int x) { siz[x] = 1; for(int i = h[x], v; i; i = e[i].nxt) { if ((v = e[i].to) == fa[x]) continue; dis[v] = dis[x] + e[i].w, fa[v] = x, dfs1(v), siz[x] += siz[v]; if (siz[son[x]] < siz[v]) son[x] = v; } } void dfs2(int x, int t) { top[x] = t, dfn[x] = ++dfc, rev[dfc] = x; if (son[x]) dfs2(son[x], t); for(int i = h[x], v; i; i = e[i].nxt) { if ((v = e[i].to) == fa[x] || v == son[x]) continue; dfs2(v, v); } } int ls[SZ], rs[SZ], tag[SZ]; LL sum[SZ]; void Modify(int &p, int u, int l, int r, int x, int y) { p = ++size, ls[p] = ls[u], rs[p] = rs[u], tag[p] = tag[u]; sum[p] = sum[u] + f[min(r, y)] - f[max(l, x) - 1]; if (x <= l && r <= y) return ++tag[p], void(); int mid = (l + r) >> 1; if (x <= mid) Modify(ls[p], ls[u], l, mid, x, y); if (y > mid) Modify(rs[p], rs[u], mid + 1, r, x, y); } LL Query(int p, int u, int l, int r, int x, int y) { if (x <= l && r <= y) return sum[p] - sum[u]; LL res = (f[min(r, y)] - f[max(l, x) - 1]) * (tag[p] - tag[u]); int mid = (l + r) >> 1; if (ls[p] && x <= mid) res += Query(ls[p], ls[u], l, mid, x, y); if (rs[p] && y > mid) res += Query(rs[p], rs[u], mid + 1, r, x, y); return res; } IN int find1(int x) { int l = 1, r = n, mid = l + r >> 1, res = 0; for(; l <= r; mid = l + r >> 1) if (a[mid].v >= x) res = mid, r = mid - 1; else l = mid + 1; return res; } IN int find2(int x) { int l = 1, r = n, mid = l + r >> 1, res = 0; for(; l <= r; mid = l + r >> 1) if (a[mid].v <= x) res = mid, l = mid + 1; else r = mid - 1; return res; } int main() { scanf("%d%d%d", &n, &q, &A); for(int i = 1; i <= n; i++) scanf("%d", &a[i].v), a[i].id = i; sort(a + 1, a + n + 1, cmp); for(int i = 1, u, v, w; i < n; i++) scanf("%d%d%d", &u, &v, &w), add(u, v, w), add(v, u, w); dfs1(1), dfs2(1, 1); for(int i = 1; i <= n; i++) f[i] = f[i - 1] + dis[rev[i]] - dis[fa[rev[i]]], sd[i] = sd[i - 1] + dis[a[i].id]; for(int i = 1, x, fx, pre; i <= n; i++) for(pre = rt[i - 1], x = a[i].id; x; pre = rt[i]) fx = top[x], Modify(rt[i], pre, 1, n, dfn[fx], dfn[x]), x = fa[fx]; LL ans = 0; for(int x, y, l, r, L, R, fx; q; q--) { scanf("%d%d%d", &x, &l, &r), l = (l + ans) % A, r = (r + ans) % A; if (l > r) swap(l, r); L = find1(l), R = find2(r), y = x, ans = 0; for(; x; ) fx = top[x], ans += Query(rt[R], rt[L - 1], 1, n, dfn[fx], dfn[x]), x = fa[fx]; printf("%lld\n", ans = dis[y] * (R - L + 1) + sd[R] - sd[L - 1] - ans * 2); } }