全局平衡二叉树
全局平衡二叉树
考虑重链剖分的时候,我们实际上是对每条重链的这个局部开一个数据结构维护,而LCT是对整颗树去维护一个大splay,考虑将LCT的思想应用到轻重链剖分中。
或者
考虑LCT维护动态dp的时候,每次进行树的形态调整常数是不是过大了,那么考虑运用静态的链剖分,用一个形态不变的平衡树维护整颗树。
实际上,全局平衡二叉树是一颗二叉树森林,其中的每颗二叉树维护一条重链。但是这个森林里的二叉树又互有联系,其中每个二叉树的根连向这个重链链头的父亲,就像LCT中一样。
我们的目的是使这个大二叉树森林树高\(\log\)。
于是我们对一条重链构建二叉树的时候,实际上可以理解成每个点点权是带权的,点权为轻子树的点数和+1,然后每次我们取这个链的带权中点作为根,递归处理子树。
这就是全局平衡二叉树的构造方法。
在做动态dp修改的时候,如果是二叉树中的父亲是另一条重链中的点,就先把自己的旧贡献去掉,再把新贡献加上,最后updata父亲,否则直接updata父亲就好
Code:
#include <cstdio>
#include <cctype>
#include <algorithm>
using std::max;
const int SIZE=(1<<21)+1;
char ibuf[SIZE],*iS=ibuf,*iT=ibuf;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
template <class T>
void read(T &x)
{
int f=0;x=0;char c=gc();
while(!isdigit(c)) f|=c=='-',c=gc();
while(isdigit(c)) x=x*10+c-'0',c=gc();
if(f) x=-x;
}
const int N=1e6+10;
int n,m,val[N];
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
struct Matrix
{
int a,b,c,d;
Matrix(){}
Matrix(int A,int B,int C,int D){a=A,b=B,c=C,d=D;}
Matrix friend operator *(Matrix a,Matrix b)
{
Matrix ret;
ret.a=max(a.a+b.a,a.b+b.c);
ret.b=max(a.a+b.b,a.b+b.d);
ret.c=max(a.c+b.a,a.d+b.c);
ret.d=max(a.c+b.b,a.d+b.d);
return ret;
}
}dat[N],mx[N];
int ch[N][2],par[N],root;
#define ls ch[now][0]
#define rs ch[now][1]
#define fa par[now]
void updata(int now)
{
mx[now]=dat[now];
if(ls) mx[now]=mx[ls]*mx[now];
if(rs) mx[now]=mx[now]*mx[rs];
}
int siz[N],lsiz[N],dp[N][2],ws[N];
void dfs(int now,int f)
{
siz[now]=lsiz[now]=1;
dp[now][1]=val[now];
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=f)
{
dfs(v,now);
siz[now]+=siz[v];
if(siz[ws[now]]<siz[v]) ws[now]=v;
}
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=f&&v!=ws[now])
{
lsiz[now]+=siz[v];
dp[now][1]+=dp[v][0];
dp[now][0]+=max(dp[v][0],dp[v][1]);
}
dat[now]=Matrix(dp[now][0],dp[now][0],dp[now][1],-(1<<30));
dp[now][1]+=dp[ws[now]][0];
dp[now][0]+=max(dp[ws[now]][0],dp[ws[now]][1]);
}
int s[N],si[N],tot;
int build(int l,int r)
{
if(l>r) return 0;
int mid=std::lower_bound(si+l,si+r+1,si[r]+si[l-1]>>1)-si,now=s[mid];
ls=build(l,mid-1);
rs=build(mid+1,r);
if(ls) par[ls]=now;
if(rs) par[rs]=now;
updata(now);
return now;
}
int dfs1(int now,int f)
{
int rt;
s[++tot]=now;
si[tot]+=lsiz[now];
if(ws[now])
{
si[tot+1]+=si[tot];
rt=dfs1(ws[now],now);
}
else
{
int now=build(1,tot);
for(int i=1;i<=tot;i++) si[i]=0;
tot=0;
return now;
}
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=f&&v!=ws[now])
par[dfs1(v,now)]=now;
return rt;
}
bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;}
void upt(int now)
{
if(!now) return;
Matrix las=mx[now];
updata(now);
if(fa&&!isroot(now))
{
dat[fa].b=(dat[fa].a+=max(mx[now].a,mx[now].c)-max(las.a,las.c));
dat[fa].c+=mx[now].a-las.a;
}
upt(fa);
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++) read(val[i]);
for(int u,v,i=1;i<n;i++) read(u),read(v),add(u,v),add(v,u);
dfs(1,0);
root=dfs1(1,0);
for(int las=0,x,y,i=1;i<=m;i++)
{
read(x),read(y);
x^=las;
dat[x].c+=y-val[x];
val[x]=y;
upt(x);
printf("%d\n",las=max(mx[root].a,mx[root].c));
}
return 0;
}