芝士:树剖

背景

对于一棵树上我们需要查找两个点之间的距离时,很多人的第一反应就是LCA

但是如果加上修改操作呢?就只能用树剖了

操作

基本变量

重量:子树的大小

重儿子:就是最重的那个儿子,

轻儿子:不是重儿子

重链:重儿子组成的链

思想

基于路径的分治,

用线段树来维护重链,

复杂度证明

我们设当前的点为u,当前点的父节点为v

如果v向u的连的边为轻边,

这说明了u不是v的重儿子

也就说明了\(size_v>2*size_u\)

然而总共的点的个数一共就n,

所以一条链上的轻边一定最多有\(log_n\)

所以向上的复杂度为\(O(log_n)\)

如果v向u连的边为重边

说明u是重儿子,

所以v向u连的边一定是重边

而我们上面又说是用线段树来维护重链时间复杂度为\(O(log_n)\)

而重链一定与轻边相连,轻边最多有\(log_n\)条,所以重链最多有\(log_n\)

总的时间复杂度即为\(O(log_nlog_n)\)

板子

struct tree_chain_split
{
    #define MAXN 100005
    struct node
    {
        int l;
        int r;
        int lazy;
        int val;
    }tre[4*MAXN];
    void build(int l,int r,int k)
    {
        tre[k].l=l;
        tre[k].r=r;
        tre[k].lazy=0;
        tre[k].val=0;
        if(l==r)
            return;
        int mid=(l+r)>>1;
        build(l,mid,k<<1);
        build(mid+1,r,k<<1|1);
    }
    void pushdown(int k)
    {
        if(tre[k].lazy==0)
            return;
        tre[k<<1].lazy+=tre[k].lazy;
        tre[k<<1|1].lazy+=tre[k].lazy;
        tre[k<<1].val+=tre[k].lazy*(tre[k<<1].r-tre[k<<1].l+1);
        tre[k<<1|1].val+=tre[k].lazy*(tre[k<<1|1].r-tre[k<<1|1].l+1);
        tre[k].lazy=0;
    }
    void change_poi(int pos,int k,int add)
    {
        if(pos>tre[k].r||pos<tre[k].l)
            return;
        if(tre[k].l==tre[k].r)
        {
            tre[k].val=tre[k].val+add;
            return;
        }
        pushdown(k);
        change_poi(pos,k<<1,add);
        change_poi(pos,k<<1|1,add);
        tre[k].val=tre[k<<1].val+tre[k<<1|1].val;
    }
    void change_int(int l,int r,int k,int add)
    {
        if(l>tre[k].r||tre[k].l>r)
            return;
        if(l<=tre[k].l&&tre[k].r<=r)
        {
            tre[k].val=tre[k].val+add*(tre[k].r-tre[k].l+1);
            tre[k].lazy=tre[k].lazy+add;
            return;
        }
        pushdown(k);
        change_int(l,r,k<<1,add);
        change_int(l,r,k<<1|1,add);
        tre[k].val=tre[k<<1].val+tre[k<<1|1].val;
    }
    int query(int l,int r,int k)
    {
        if(l>tre[k].r||tre[k].l>r)
            return 0;
        if(l<=tre[k].l&&tre[k].r<=r)
            return tre[k].val;
        pushdown(k);
        return query(l,r,k<<1)+query(l,r,k<<1|1);
    }
    int cnt;
    int w[MAXN];
    int fa[MAXN];
    int id[MAXN];
    int siz[MAXN];
    int top[MAXN];
    int dep[MAXN];
    int wson[MAXN];
    vector<int> g[MAXN];
    #undef MAXN
    void addedge(int u,int v)
    {
        g[u].push_back(v);
    }
    void dfs1(int u)
    {
        siz[u]=1;
        dep[u]=dep[fa[u]]+1;
        int maxx=-1;
        int _ind=0;
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            if(v!=fa[u])
            {
                fa[v]=u;
                dfs1(v);
                siz[u]+=siz[v];
                if(siz[v]>maxx)
                {
                    maxx=siz[v];
                    _ind=v;
                }
            }
        }
        wson[u]=_ind;
    }
    void dfs2(int u,int top_chain)
    {
        top[u]=top_chain;
        id[u]=++cnt;
        change_poi(cnt,1,w[u]);
        if(!wson[u])
            return;
        dfs2(wson[u],top_chain);
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            if(v!=fa[u]&&v!=wson[u])
                dfs2(v,v);
        }
    }
    void init(int len)
    {
        cnt=0;
        build(1,len,1);
        dfs1(rt);
        dfs2(rt,rt);
    }
    void change_int(int x,int y,int add)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
                swap(x,y);
            change_int(id[top[y]],id[y],1,add);
            y=fa[top[y]];
        }
        if(dep[x]>dep[y])
            swap(x,y);
        change_int(id[x],id[y],1,add);
    }
    int query(int x,int y)
    {
        int ret=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
                swap(x,y);
            ret=ret+query(id[top[y]],id[y],1);
            y=fa[top[y]];
        }
        if(dep[x]>dep[y])
            swap(x,y);
        ret=ret+query(id[x],id[y],1);
        return ret;
    }
    void change_rot(int x,int add)
    {
        change_int(id[x],id[x]+siz[x]-1,1,add);
    }
    int query_rot(int x)
    {
        return query(id[x],id[x]+siz[x]-1,1);
    }
}tre;

猜你喜欢

转载自www.cnblogs.com/loney-s/p/12158092.html