1. 程式人生 > 其它 >雜湊表 --- 模擬散列表

雜湊表 --- 模擬散列表

\(\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);
	}
}