[HNOI2015]开店
\(\text{Problem}\)
给你一棵树,点带权 \(a_x\),边带权,每次询问给个点 \(x\)
询问所有 \(y\) 满足 \(L\le a_y \le R\),求 \(\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);
}
}