全局平衡二叉樹


全局平衡二叉樹

考慮重鏈剖分的時候,我們實際上是對每條重鏈的這個局部開一個數據結構維護,而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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM