#2558. 「LNOI2014」LCA

将 \(\sum lca_{i, z}\) 的贡献拆分到每个 \(lca\) 到根的路径的结点,相当于统计 \(lca\) 到根的路径上点的点权和。

对于每个操作,可以依次将 \(l \cdots r\) 把到它们到根路径上结点加 \(1\),答案就是最后 \(z\) 到根路径的点权和,

可以通过处理出加入 \(1...l - 1\),\(1...r\) 的 \(z\) 到根路径的和,相减即为答案。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define fi first
#define se second
const int N = 1e5 + 10, inf = 0x3f3f3f3f, mod = 201314;
typedef pair <int, int> P;
typedef long long LL;

struct Edge {
	int to, next;
} e[N];
vector <P> g[N];
int n, q, fa[N], h[N], cnt, tot;
int d[N], son[N], siz[N], st[N], top[N];
LL ans[N];
struct Tree {
	LL v[N<<2]; int add[N<<2];
	void down_(int o, int l, int r) {
		int mid = (l + r)>>1, ls = o<<1, rs = o<<1|1;
		v[ls] += (mid - l + 1)*add[o], v[rs] += (r - mid)*add[o];
		add[ls] += add[o], add[rs] += add[o];
		add[o] = 0;
	}
	void add_(int o, int l, int r, int x, int y, int k) {
		if (x <= l && r <= y) {
			v[o] += (r - l + 1)*k, add[o] += k;
			return;
		}
		if (add[o]) down_(o, l, r);
		int mid = (l + r)>>1;
		if (x <= mid) add_(o<<1, l, mid, x, y, k);
		if (mid < y) add_(o<<1|1, mid + 1, r, x, y, k);
		v[o] = v[o<<1] + v[o<<1|1];
	} 
	LL sum_(int o, int l, int r, int x, int y) {
		if (x <= l && r <= y) return v[o];
		if (add[o]) down_(o, l, r);
		int mid = (l + r)>>1;
		LL res = 0;
		if (x <= mid) res += sum_(o<<1, l, mid, x, y);
		if (mid < y) res += sum_(o<<1|1, mid + 1, r, x, y);
		return res;
	}  
} T;

void add_(int u, int v) {
	e[++cnt] = (Edge) {v, h[u]};
	h[u] = cnt;
}

void dfs2_(int u, int topf) {
	top[u] = topf, st[u] = ++tot;
	if (son[u]) dfs2_(son[u], topf);
	for (int v, i = h[u]; i; i = e[i].next) {
		v = e[i].to;
		if (v != son[u]) dfs2_(v, v);
	}
}

void dfs1_(int u) {
	d[u] = d[fa[u]] + 1, siz[u] = 1;
	for (int v, i = h[u]; i; i = e[i].next) {
		v = e[i].to;
		dfs1_(v);
		siz[u] += siz[v];
		if (siz[v] > siz[son[u]]) son[u] = v;
	}
}

void solve_() {
	dfs1_(1), dfs2_(1, 1);
	rep (i, 1, n) {
		int u = i;
		while (top[u] != 1) {
			T.add_(1, 1, n, st[top[u]], st[u], 1);
			u = fa[top[u]];
		}
		//cout<<"OK";
		T.add_(1, 1, n, 1, st[u], 1);
		rep (j, 0, (int) g[i].size() - 1) {
			u = g[i][j].fi;
			while (top[u] != 1) {
				ans[abs(g[i][j].se)] += g[i][j].se/abs(g[i][j].se)*T.sum_(1, 1, n, st[top[u]], st[u]);
				u = fa[top[u]];
			}
			ans[abs(g[i][j].se)] += g[i][j].se/abs(g[i][j].se)*T.sum_(1, 1, n, 1, st[u]);
		}
	}
}

int main() {
	scanf("%d%d", &n, &q);
	rep (i, 2, n) {
		scanf("%d", &fa[i]), fa[i]++;
		add_(fa[i], i);
	}
	for (int l, r, z, i = 1; i <= q; i++) {
		scanf("%d%d%d", &l, &r, &z), l++, r++, z++;
		g[l - 1].push_back(P(z, -i));
		g[r].push_back(P(z, i));
	}
	solve_();
	rep (i, 1, q) printf("%lld\n", ans[i]%mod);
	return 0;
}
上一篇:【LCA+树上差分】P3258 [JLOI2014] 松鼠的新家


下一篇:【Codeforces 1083C】Max Mex(线段树 & LCA)