Luogu P4338 - [ZJOI2018] history (LCT)

Posted by dnszero on Sat, 05 Mar 2022 12:22:35 +0100

Problem plane portal

A good LCT practice problem.

First, consider how to deal with the situation without modification. Note that for a \ (U \), if we dye the subtree of each son of \ (U \) with one color and the point of \ (U \) with one color, when we access a point \ (v \) in the subtree of \ (U \), the point \ (u \) will contribute \ (1 \) to the answer, if and only if the last accessed point in the subtree of \ (U \) is not of the same color as \ (v \), Therefore, if every point is a leaf except for the \ (1 \) node, the problem will be transformed into a classic problem: there are \ (n \) colors, and there are \ (a_i \) points in the \ (I \) color. Now we need to line up these \ (\ sum \ limits {I = 1} ^ na_i \) points to maximize the number of adjacent different colors. This is a classic question. According to the classic greedy conclusion, the answer to the above question is \ (\ min (\ sum \ limits {I = 1} ^ Na _i-1, (\ sum \ limits {I = 1} ^ Na _i - \ Max \ limits {I = 1} ^ Na _i) \ times 2) \). What if the picture is not a chrysanthemum? In fact, it's easy to do. Consider how to determine the access order of points in the \ (U \) subtree: we first recursively determine the access order of points in all son subtrees, then regard the subtrees corresponding to all sons of \ (U \) as one color, and set the number of sons of \ (U \) points as \ (C \), then we calculate the optimal scheme to arrange the points in the \ (U \) subtree according to the above classical conclusion, The internal access order of the same color is arranged according to the order we previously set for each son's subtree, which can be recursive. This tells us that the contribution of each point can be calculated independently and can be solved by DFS once. Specifically, let \ (f (a_1, a_2, \ cdots, a_n) = \ min (\ sum \ limits {I = 1} ^ na_i-1, (\ sum \ limits {I = 1} ^ na_i - \ Max \ limits {I = 1} ^ na_i) \ times 2) \), the point \ (U \) has \ (c_i \) sons \ (son {u, 1}, son {u, 2}, \ cdots, son {u, c_} \), and the sum of \ (a \) of all points in the \ (U \) subtree is \ (sum _ \), Then the answer is \ (\ sum \ limits {I = 1} ^ NF (sum {son {u, 1}}, sum {son {u, 2}}, \ cdots, sum {son {u, C}}, a _) \).

Next, consider how to deal with the band modification. It can be found that this problem is a bit of chain splitting, because for each point \ (u \), according to the above sum formula, the contribution of \ (u \) point is only related to the largest of \ (sum \) and \ (sum \) among the sons of \ (u \). Therefore, if we call the largest of \ (sum \) among the sons of \ (u \) as "heavy son", Then a "weighted chain subdivision" model is formed. Therefore, we consider that for a point \ (u \), the largest of its sons \ (sum \) is \ (wson_ \), so if \ (sum_ {wson_} \ times 2 > sum_ \), we connect sides \ (u \ to wson_ \), which will obviously form a chain of ancestors \ (\ to \) offspring. More specifically, there are only \ (\ log nV \) heavy chains on each point to the root path, This can be analyzed by a method similar to heavy chain subdivision. When we modify the point weight of a point \ (u \), we consider a heavy chain on the path from \ (u \) to the root node. It is not difficult to find that the contribution of the point in the middle of the heavy chain will not change, and the only possible change is the top node of the chain, which inspires us to use LCT to maintain each chain and deduct the answer of the original top of the chain every time we modify it, After modification, add a new answer to the chain top and update the structure of chain subdivision.

Can do \ (n\log nV \), but the following code is \ (n\log n\log nV \):

const int MAXN = 5e5;
int n, qu, hd[MAXN + 5], to[MAXN * 2 + 5], nxt[MAXN * 2 + 5], ec, fa[MAXN + 5];
void adde(int u, int v) {to[++ec] = v; nxt[ec] = hd[u]; hd[u] = ec;}
int dfn[MAXN + 5], edt[MAXN + 5], tim, wson[MAXN + 5];
ll res = 0, a[MAXN + 5];
ll t[MAXN + 5];
void add(int x, ll v) {for (int i = x; i <= n; i += (i & (-i))) t[i] += v;}
ll query(int x) {ll ret = 0; for (int i = x; i; i &= (i - 1)) ret += t[i]; return ret;}
ll qry(int x) {return (!x) ? 0 : (query(edt[x]) - query(dfn[x] - 1));}
ll clc(int x) {return min(qry(x) - 1, (qry(x) - max(a[x], qry(wson[x]))) * 2);}
void dfs(int x, int f) {
	dfn[x] = ++tim; add(tim, a[x]); fa[x] = f;
	for (int e = hd[x]; e; e = nxt[e]) {
		int y = to[e]; if (y == f) continue; dfs(y, x);
		if (qry(y) > qry(wson[x])) wson[x] = y;
	}
	edt[x] = tim; res += clc(x);
}
struct node {int ch[2], f;} s[MAXN + 5];
int ident(int k) {return ((s[s[k].f].ch[0] == k) ? 0 : ((s[s[k].f].ch[1] == k) ? 1 : -1));}
void connect(int k, int f, int op) {s[k].f = f; if (~op) s[f].ch[op] = k;}
void rotate(int x) {
	int y = s[x].f, z = s[y].f, dx = ident(x), dy = ident(y);
	connect(s[x].ch[dx ^ 1], y, dx); connect(y, x, dx ^ 1); connect(x, z, dy);
}
void splay(int k) {
	while (~ident(k)) {
		if (!~ident(s[k].f)) rotate(k);
		else if (ident(k) == ident(s[k].f)) rotate(s[k].f), rotate(k);
		else rotate(k), rotate(k);
	}
}
int qrymn(int k) {while (s[k].ch[0]) k = s[k].ch[0]; return k;}
int main() {
	scanf("%d%d", &n, &qu);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), adde(u, v), adde(v, u);
	dfs(1, 0); printf("%lld\n", res);
	for (int i = 1; i <= n; i++) s[i].f = fa[i];
	for (int i = 1; i <= n; i++) if (wson[i] && qry(wson[i]) * 2 > qry(i))
		s[i].ch[1] = wson[i];
	while (qu--) {
		int x, v; scanf("%d%d", &x, &v); map<int, int> vis;
		for (int y = x; y; y = s[y].f) splay(y), res -= clc(y);
		add(dfn[x], v); a[x] += v;
		int pre = 0, prex = 0;
		for (int y = x; y; prex = y, y = s[y].f) {
			splay(y); //printf("! %d\n", y);
			if (pre && qry(pre) > qry(wson[y])) {
				wson[y] = pre; s[y].ch[1] = prex;
			}
			if (qry(wson[y]) * 2 <= qry(y)) s[y].ch[1] = 0;
			res += clc(y); pre = qrymn(y);
		}
		printf("%lld\n", res);
	}
	return 0;
}
/*
5 8
1 1 1 1 1
1 2
2 3
3 4
4 5
3 10
4 100
5 1000
2 10000
3 100000
1 200000
3 300000
5 400000
*/