「ZJOI2018」历史(找性质+重链剖分+lct)

https://loj.ac/problem/2434

先考虑\(a[i]\)确定时,答案怎么求?

\(s[x]\)表示\(x\)为根的子树的\(a\)的和。

对于每一个\(x\)为根的子树,假设确定了\(x\)的儿子的子树的答案,接下来合并,那么显然是尽可能插空合并。

\(max=max(a[x],s[y1],s[y2]…)\),当\(2*max<=s[x]\)时,可以保证任意相邻两个都是来自不同子树,则\(ans+=s[x]-1\)

否则,\(ans+=s[x]-1-(max-(s[x]-max)-1)=2s[x]-2max\),统计一下即可。

为了方便,我们把\(x\)上的权值扔到单独建的一个点\(x'\),这个点的父亲是\(x\),这样可以把它当成子树看。

带修改:
考虑轻重链剖分,每个点的\(son[x]\)是唯一(也可能没有)的那个\(2s[y]>s[x]\)\(y\)

此时,任何点到根经过的轻链数量依然满足\(\le log\sum a[i]\)

那么每次修改时,因为每次都是加,所以只会把轻链修改成重链。

用lct维护重链,每次找到轻链,稍微讨论并对全局变量\(ans\)进行修改。

时间复杂度\(O(n~log~n~log\sum a[i])\)

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 8e5 + 5;

int n, m, x, y;

#define V vector<int>
#define pb push_back
#define si size()

V e[N]; int fq[N];
void dg(int x) {
	ff(_y, 0, e[x].si) {
		int y = e[x][_y]; if(y == fq[x]) continue;
		fq[y] = x;
		dg(y);
	}
}

ll a[N], s[N], lz[N];

#define x0 t[x][0]
#define x1 t[x][1]
int t[N][2], fa[N], pf[N];
void upd(int x) {
	
}
void jia(int x, ll v) {
	if(x) s[x] += v, lz[x] += v;
}
void down(int x) {
	if(lz[x]) {
		jia(x0, lz[x]);
		jia(x1, lz[x]);
		lz[x] = 0;
	}	
}
int lr(int x) { return t[fa[x]][1] == x;} 
void ro(int x) {
	int y = fa[x], k = lr(x);
	t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y;
	fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x;
	fa[y] = x; t[x][!k] = y; pf[x] = pf[y];
	upd(y); upd(x);
}
int dd[N];
void xc(int x) {
	for(; x; x = fa[x]) dd[++ dd[0]] = x;
	while(dd[0]) down(dd[dd[0] --]);
}
void sp(int x, int y) {
	xc(x);
	for(; fa[x] != y; ro(x)) if(fa[fa[x]] != y)
		ro(lr(x) == lr(fa[x]) ? fa[x] : x);
}
int fl(int x) { return x0 ? fl(x0) : x;} 

ll ans;

void add(int x, ll v) {
	for(int y = 0; x; )	{
		sp(x, 0); down(x);
		if(x > n) {
			if(!x1) {
				ans += v;
			} else {
				int z = fl(x1); sp(z, x);
				if(2 * s[x1] <= s[x] + v) {
					ans -= 2 * s[x] - 2 * s[x1];
					ans += s[x] + v - 1;
					fa[x1] = 0, pf[x1] = x; x1 = 0;
				} else {
					ans += 2 * v;
				}
			}
		}
		jia(x0, v); s[x] += v;
		if(y) {
			if(2 * s[y] > s[x]) {
				ans -= s[x] - 1;
				ans += 2 * s[x] - 2 * s[y];
				x1 = y; fa[y] = x; pf[y] = 0;
			}
		}
		x = fl(x), sp(x, 0);
		upd(x), y = x, x = pf[x];
	}
}

int main() {
	scanf("%d %d", &n, &m);
	fo(i, 1, n) scanf("%lld", &a[i]);
	fo(i, 1, n - 1) {
		scanf("%d %d", &x, &y);
		e[x].pb(y); e[y].pb(x);
	}
	dg(1);
	ans = -n;
	fo(i, 2, n) pf[i + n] = fq[i] + n;
	fo(i, 1, n) pf[i] = i + n;
	fo(i, 1, n) add(i, a[i]);
	pp("%lld\n", ans);
	fo(ii, 1, m) {
		scanf("%d %d", &x, &y);
		add(x, y);
		pp("%lld\n", ans);
	}
} 
posted @ 2020-04-11 21:32  Cold_Chair  阅读(171)  评论(0编辑  收藏  举报