「ZJOI2018」历史(找性质+重链剖分+lct)
先考虑\(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);
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址