全局平衡二叉树

全局平衡二叉树

考虑重链剖分的时候,我们实际上是对每条重链的这个局部开一个数据结构维护,而LCT是对整颗树去维护一个大splay,考虑将LCT的思想应用到轻重链剖分中。

或者

考虑LCT维护动态dp的时候,每次进行树的形态调整常数是不是过大了,那么考虑运用静态的链剖分,用一个形态不变的平衡树维护整颗树。


实际上,全局平衡二叉树是一颗二叉树森林,其中的每颗二叉树维护一条重链。但是这个森林里的二叉树又互有联系,其中每个二叉树的根连向这个重链链头的父亲,就像LCT中一样。

我们的目的是使这个大二叉树森林树高\(\log\)

于是我们对一条重链构建二叉树的时候,实际上可以理解成每个点点权是带权的,点权为轻子树的点数和+1,然后每次我们取这个链的带权中点作为根,递归处理子树。

这就是全局平衡二叉树的构造方法。

在做动态dp修改的时候,如果是二叉树中的父亲是另一条重链中的点,就先把自己的旧贡献去掉,再把新贡献加上,最后updata父亲,否则直接updata父亲就好

洛谷P4751 【模板】动态 DP(加强版)

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;
}
posted @ 2019-04-28 11:38  露迭月  阅读(3387)  评论(0编辑  收藏  举报