ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

树上链翻转,链加,查询链上的和/max/min

树链剖分套treap,修改查询可以用类似线段树的写法,翻转可以利用分裂合并和翻转标记实现,时间复杂度O(nlog2n)

实测除了翻转之外的操作常数较小,翻转由于需要把整条链拆出来再合并回去,稍慢一些

#include<cstdio>
#include<algorithm>
typedef long long i64;
const int N=50007;
int _(){
    int x;scanf("%d",&x);return x;
}
i64 _a;
void maxs(i64&a,i64 b){if(a<b)a=b;}
void mins(i64&a,i64 b){if(a>b)a=b;}
struct node{
    node*lc,*rc;
    int sz,rnd,rv;
    i64 a,v,s,mx,mn;
    void _rev(){
        if(!this)return;
        rv^=1;
        std::swap(lc,rc);
    }
    void _add(i64 x){
        if(!this)return;
        a+=x;v+=x;
        mx+=x;mn+=x;
        s+=x*sz;
    }
    void dn(){
        if(rv){
            lc->_rev();
            rc->_rev();
            rv=0;
        }
        if(a){
            lc->_add(a);
            rc->_add(a);
            a=0;
        }
    }
    void up(){
        sz=1;s=v;
        mx=mn=v;
        if(lc){
            sz+=lc->sz;
            s+=lc->s;
            maxs(mx,lc->mx);
            mins(mn,lc->mn);
        }
        if(rc){
            sz+=rc->sz;
            s+=rc->s;
            maxs(mx,rc->mx);
            mins(mn,rc->mn);
        }
    }
    void sp(int k,node*&l,node*&r){
        if(!this){l=r=0;return;}
        int ls=lc?lc->sz:0;
        dn();
        if(k<=ls)lc->sp(k,l,lc),r=this;
        else rc->sp(k-ls-1,rc,r),l=this;
        up();
    }
    node*mg(node*a){
        if(!a)return this;
        if(!this)return a;
        if(rnd>a->rnd){
            dn();
            rc=rc->mg(a);
            up();
            return this;
        }
        a->dn();
        a->lc=mg(a->lc);
        a->up();
        return a;
    }
    #define DEF(A,B,C) \
    void A(int l,int r){\if(!this||r<=0||l>=sz)return;\
        if(l<=0&&r>=sz){B;return;}\
        int ls=lc?lc->sz:0;\
        dn();\
        if(l<=ls&&r>ls)C;\
        if(l<ls)lc->A(l,r);\
        if(r>ls+1)rc->A(l-ls-1,r-ls-1);\
        up();\
    }
    DEF(add,_add(_a),v+=_a)
    DEF(gmx,maxs(_a,mx),maxs(_a,v))
    DEF(gmn,mins(_a,mn),mins(_a,v))
    DEF(sum,_a+=s,_a+=v)
    #undef DEF
}ns[N],*rt[N];
int es[N*2],enx[N*2],e0[N],ep=2;
int fa[N],sz[N],son[N],dep[N],top[N];
void f1(int w,int pa){
    dep[w]=dep[fa[w]=pa]+1;
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]>sz[son[w]])son[w]=u;
        }
    }
}
void f2(int w,int tp){
    top[w]=tp;
    rt[tp]=rt[tp]->mg(ns+w);
    if(son[w])f2(son[w],tp);
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=fa[w]&&u!=son[w])f2(u,u);
    }
}
#define DEF(A) \
void A(int x,int y){\
    int a=top[x],b=top[y];\
    while(a!=b){\
        if(dep[a]<dep[b])std::swap(a,b),std::swap(x,y);\
        rt[a]->A(0,dep[x]-dep[a]+1);\
        x=fa[a],a=top[x];\
    }\
    if(dep[x]>dep[y])std::swap(x,y);\
    rt[a]->A(dep[x]-dep[a],dep[y]-dep[a]+1);\
}
DEF(add)
DEF(gmx)
DEF(gmn)
DEF(sum)
#undef DEF
node*s1[40][3],*s2[40][3];
int sz1[40],w1[40],sz2[40],w2[40];
void rev(int x,int y){
    if(x==y)return;
    int a=top[x],b=top[y],p1=0,p2=0;
    while(a!=b){
        if(dep[a]>dep[b]){
            s1[p1][0]=0;
            rt[a]->sp(dep[x]-dep[a]+1,s1[p1][1],s1[p1][2]);
            w1[p1]=a;
            sz1[p1]=s1[p1][1]->sz;
            ++p1;
            x=fa[a],a=top[x];
        }else{
            s2[p2][0]=0;
            rt[b]->sp(dep[y]-dep[b]+1,s2[p2][1],s2[p2][2]);
            w2[p2]=b;
            sz2[p2]=s2[p2][1]->sz;
            ++p2;
            y=fa[b],b=top[y];
        }
    }
    if(dep[x]>dep[y]){
        rt[a]->sp(dep[y]-dep[a],s1[p1][0],s1[p1][1]);
        s1[p1][1]->sp(dep[x]-dep[y]+1,s1[p1][1],s1[p1][2]);
        w1[p1]=a;
        sz1[p1]=s1[p1][1]->sz;
        ++p1;
    }else{
        rt[a]->sp(dep[x]-dep[a],s2[p2][0],s2[p2][1]);
        s2[p2][1]->sp(dep[y]-dep[x]+1,s2[p2][1],s2[p2][2]);
        w2[p2]=a;
        sz2[p2]=s2[p2][1]->sz;
        ++p2;
    }
    node*p=0;
    for(int i=0;i<p1;++i)p=s1[i][1]->mg(p);
    p->_rev();
    for(int i=p2-1;i>=0;--i)p=p->mg(s2[i][1]);
    for(int i=0;i<p1;++i)p->sp(p->sz-sz1[i],p,s1[i][1]);
    p->_rev();
    for(int i=p2-1;i>=0;--i)p->sp(sz2[i],s2[i][1],p);
    for(int i=0;i<p1;++i)rt[w1[i]]=s1[i][0]->mg(s1[i][1])->mg(s1[i][2]);
    for(int i=0;i<p2;++i)rt[w2[i]]=s2[i][0]->mg(s2[i][1])->mg(s2[i][2]);
}
int n,m,r;
char op[16];
int main(){
    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=n;++i)ns[i].rnd=rand()|1,ns[i].sz=1;
    for(int i=1,a,b;i<n;++i){
        scanf("%d%d",&a,&b);
        es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
        es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
    }
    f1(1,0);
    f2(1,1);
    while(m--){
        int x,y,z;
        scanf("%s%d%d",op,&x,&y);
        if(op[2]=='c'){
            scanf("%d",&z);
            _a=z;
            add(x,y);
        }else if(op[2]=='m'){
            _a=0;
            sum(x,y);
            printf("%lld\n",_a);
        }else if(op[2]=='j'){
            _a=-(1ll<<60);
            gmx(x,y);
            printf("%lld\n",_a);
        }else if(op[2]=='n'){
            _a=1ll<<60;
            gmn(x,y);
            printf("%lld\n",_a);
        }else{
            rev(x,y);
        }
    }
    return 0;
}

 

posted on 2017-05-03 20:49  nul  阅读(316)  评论(0编辑  收藏  举报