全局平衡二叉树学习笔记

89 篇文章 0 订阅
72 篇文章 0 订阅

感觉是树剖和lct的一种结合,把树剖的log^2变成log,把lct的常数变小,但是能维护的东西也有局限性...

实际上就是有时候维护的东西不需要lct的link-cut操作,所以可以将树建成一棵棵二叉平衡树连在一起而不需要splay。具体建法就是先轻重链剖分,对每条重链建一棵bst,然后这棵bst的根通过虚边连向这棵bst内深度最浅的点在原树中的父亲。而对于每条重链建bst时,注意为了保证平衡,不是直接取中间的那个点,而是对重链上每个点赋一个轻儿子子树siz和的权值,找到带权中心(使左右权值和尽可能相等的点),然后递归建树。考虑一下复杂度:首先因为轻重链剖分,所以从一棵bst的根往上走一步树的大小一定*2,在考虑我们对重链建的bst按轻儿子子树大小建,这样又可以保证在bst上往上走一步树的大小也一定*2,所以这样就保证这样建的全局平衡二叉树树高是log的。

信息的维护基本就和lct维护区间信息一样,可以做一些动态dp之类的题目。

模板题:https://www.luogu.org/problemnew/show/P4751

这题很卡,交了10发1发过其它全90,看评测机温度...

代码:(其实不长都是卡常痕迹...)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
const int inf=1e9;

const int BF=1e7;
char gc()
{
    static char buf[BF];
    static int len=0,ps=0;
    if(ps==len)ps=0,len=fread(buf,1,BF,stdin);
    if(ps==len)exit(0);
    return buf[ps++];
}

template<class T>
void rd(T &x)
{
    char c=gc();x=0;bool f=0;
    while(!isdigit(c))f|=(c=='-'),c=gc();
    while(isdigit(c))x=x*10+c-48,c=gc();
    if(f)x=-x;
}

template<class T>
void print(T x)
{
    static int ppp[30],pnum;
    pnum=0;
    if(x<0)putchar('-'),x=-x;
    if(x==0)putchar('0');
    while(x)ppp[++pnum]=x%10,x/=10;
    for(int i=pnum;i>=1;i--)putchar('0'+ppp[i]);
    putchar('\n');
}

void Mx(int &x,int y)
{x=max(x,y);}

int n,m,a[N];
int son[N],siz[N];
int f[N],g[N];
vector<int>mp[N];

struct Mat{
    int a[2][2];
    Mat(){memset(a,-63,sizeof a);}
    int ask(){return max(a[0][0],a[1][0]);}
    void in(int x,int y)
    {a[0][0]=a[0][1]=x,a[1][0]=y,a[1][1]=-inf;}
};

Mat operator *(const Mat &x,const Mat &y)
{
    Mat res;
    res.a[0][0]=max(x.a[0][0]+y.a[0][0],x.a[0][1]+y.a[1][0]);
    res.a[0][1]=max(x.a[0][0]+y.a[0][1],x.a[0][1]+y.a[1][1]);
    res.a[1][0]=max(x.a[1][0]+y.a[0][0],x.a[1][1]+y.a[1][0]);
    res.a[1][1]=max(x.a[1][0]+y.a[0][1],x.a[1][1]+y.a[1][1]);
    return res;
}

void dfs0(int x,int fa)
{
    siz[x]=1,f[x]=a[x],g[x]=0;
    for(int v,i=0;i<mp[x].size();i++)
    {
        v=mp[x][i];
        if(v==fa)continue;
        dfs0(v,x),siz[x]+=siz[v];
        if(siz[v]>siz[son[x]])son[x]=v;
        f[x]+=g[v],g[x]+=max(f[v],g[v]);
    }
}

void dfs1(int x,int fa)
{
    if(son[x])
    {
        f[x]-=g[son[x]],g[x]-=max(f[son[x]],g[son[x]]);
        for(int v,i=0;i<mp[x].size();i++)
        {
            v=mp[x][i];
            if(v==fa)continue;
            dfs1(v,x);
        }
    }
}

namespace gbt{
    Mat dp[N],seg[N];
    int rt,tax[N],tnum,ch[N][2],fa[N],las_ans=0;
    bool isr(int x)
    {return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x);}
    void push_up(int x)
    {
        seg[x]=dp[x];
        if(ch[x][0])seg[x]=seg[ch[x][0]]*seg[x];
        if(ch[x][1])seg[x]=seg[x]*seg[ch[x][1]];
    }
    int bd_chain(int l,int r)
    {
        if(l>r)return 0;
        int sum=0,nw=0;
        for(int i=l;i<=r;i++)
            sum+=siz[tax[i]]-siz[son[tax[i]]];
        for(int i=l;i<=r;i++)
        {
            nw+=siz[tax[i]]-siz[son[tax[i]]];
            if(nw*2>=sum)
            {
                int x=tax[i];
                ch[x][0]=bd_chain(l,i-1);
                ch[x][1]=bd_chain(i+1,r);
                fa[ch[x][0]]=fa[ch[x][1]]=x;
                push_up(x);
                return x;
            }
        }
    }
    int bd(int top,int f)
    {
        for(int x=top;x;f=x,x=son[x])
        {
            for(int v,i=0;i<mp[x].size();i++)
            {
                v=mp[x][i];
                if(v==son[x]||v==f)continue;
                fa[bd(v,x)]=x;
            }
        }
        tnum=0;
        for(int x=top;x;x=son[x])tax[++tnum]=x;
        return bd_chain(1,tnum);	
    }
    void init()
    {
        for(int i=1;i<=n;i++)
            dp[i].in(g[i],f[i]);
        rt=bd(1,0);
    }
    void qry(int x,int y)
    {
        int bf_g,bf_f,nx_g,nx_f;
        bool flg;
        f[x]+=y-a[x],a[x]=y;
        while(x)
        {
            flg=isr(x);
            if(flg)bf_g=seg[x].a[0][0],bf_f=seg[x].a[1][0];
            dp[x].in(g[x],f[x]),push_up(x);
            if(flg)nx_g=seg[x].a[0][0],nx_f=seg[x].a[1][0];
            if(flg&&fa[x])
            {
                g[fa[x]]+=max(nx_f,nx_g)-max(bf_f,bf_g);
                f[fa[x]]+=nx_g-bf_g;
            }
            x=fa[x];
        }
        print(las_ans=seg[rt].ask());
    }
    void sol()
    {
        for(int i=1,x,y;i<=m;i++)
            rd(x),x^=las_ans,rd(y),qry(x,y);
    }
}

int main()
{
    rd(n),rd(m);
    for(int i=1;i<=n;i++)
        rd(a[i]);
    for(int u,v,i=1;i<n;i++)
    {
        rd(u),rd(v);
        mp[u].push_back(v);
        mp[v].push_back(u);
    }
    dfs0(1,0),dfs1(1,0);
    gbt::init(),gbt::sol();
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值