bzoj3159 -- LCT

因为LCT只能将路径上的点翻转而不是权值,所以不能直接用LCT做。
考虑再建一棵LCT维护权值。
查询原Splay第k个数的权值时在第二棵Splay中查找。
进行翻转操作直接将第二个LCT翻转就可以了。

代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
inline void Read(char* s){
    char c=nc();
    for(;!((c>='a'&&c<='z')||(c>='A'&&c<='Z'));c=nc());
    for(int j=0;(c>='a'&&c<='z')||(c>='A'&&c<='Z');s[j++]=c,c=nc());
}
#define N 50010
#define ll long long
int i,j,k,n,m,x,y,z;
char s[30];
struct Splay1{
    int f[N],rt[N],ch[N][2],s[N];
    bool b[N],r[N];
    inline bool Get(int x){
        return ch[f[x]][1]==x;
    }
    inline void Update_rev(int x){
        if(!x)return;
        r[x]^=1;swap(ch[x][0],ch[x][1]);
    }
    inline void Down(int x){
        if(!x)return;
        if(r[x])Update_rev(ch[x][0]),Update_rev(ch[x][1]),r[x]=0;
    }
    inline void Up(int x){
        if(!x)return;
        s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
    }
    inline void Rotate(int x){
        bool d=Get(x);int y=f[x];
        if(b[y])b[x]=1,b[y]=0,rt[x]=rt[y];else ch[f[y]][Get(y)]=x;
        ch[y][d]=ch[x][d^1];f[ch[y][d]]=y;
        f[x]=f[y];f[y]=x;ch[x][d^1]=y;Up(y);
    }
    inline void P(int x){
        if(!b[x])P(f[x]);
        Down(x);
    }
    inline void Splay(int x){
        for(P(x);!b[x];Rotate(x))
        if(!b[f[x]])Rotate(Get(x)==Get(f[x])?f[x]:x);
        Up(x);
    }
}fm;
struct Splay2{
    ll sum[N];
    int f[N],s[N],ch[N][2],ma[N],mi[N],a[N],p[N];
    bool b[N],r[N];
    inline bool Get(int x){
        return ch[f[x]][1]==x;
    }
    inline void Update_rev(int x){
        if(!x)return;
        r[x]^=1;swap(ch[x][0],ch[x][1]);
    }
    inline void Update_add(int x,int y){
        if(!x)return;
        p[x]+=y;sum[x]+=1ll*y*s[x];a[x]+=y;
        ma[x]+=y;mi[x]+=y;
    }
    inline void Up(int x){
        if(!x)return;
        s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
        sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+a[x];
        ma[x]=max(a[x],max(ma[ch[x][0]],ma[ch[x][1]]));
        mi[x]=min(a[x],min(mi[ch[x][0]],mi[ch[x][1]]));
    }
    inline void Down(int x){
        if(!x)return;
        if(p[x]){
            Update_add(ch[x][0],p[x]);Update_add(ch[x][1],p[x]);
            p[x]=0;
        }
        if(r[x])Update_rev(ch[x][0]),Update_rev(ch[x][1]),r[x]=0;
    }
    inline void Rotate(int x){
        bool d=Get(x);int y=f[x];
        if(b[y])b[x]=1,b[y]=0;else ch[f[y]][Get(y)]=x;
        ch[y][d]=ch[x][d^1];f[ch[y][d]]=y;
        f[x]=f[y];f[y]=x;ch[x][d^1]=y;Up(y);
    }
    inline void P(int x){
        if(!b[x])P(f[x]);
        Down(x);
    }
    inline void Splay(int x){
        for(P(x);!b[x];Rotate(x))
        if(!b[f[x]])Rotate(Get(x)==Get(f[x])?f[x]:x);
        Up(x);
    }
    inline int Find(int x,int y){
        y-=s[ch[x][0]]+1;
        if(!y)return x;
        Down(x);
        if(y<0)return Find(ch[x][0],y+s[ch[x][0]]+1);
        return Find(ch[x][1],y);
    }
}vl;
inline void Access(int x){
    int y=0;
    while(x){
        fm.Splay(x);
        int z=fm.rt[x];
        vl.Splay(z);
        z=vl.Find(z,fm.s[fm.ch[x][0]]+1);
        vl.Splay(z);
        fm.b[fm.ch[x][1]]=vl.b[vl.ch[z][1]]=1;
        fm.b[y]=vl.b[fm.rt[y]]=0;
        fm.rt[fm.ch[x][1]]=vl.ch[z][1];
        vl.f[vl.ch[z][1]]=0;
        vl.f[fm.rt[y]]=z;
        fm.ch[x][1]=y;vl.ch[z][1]=fm.rt[y];
        fm.rt[x]=z;
        fm.Up(y=x);vl.Up(z);
        x=fm.f[x];
    }
}
inline void mr(int x){
    Access(x);fm.Splay(x);vl.Splay(fm.rt[x]);
    fm.Update_rev(x);vl.Update_rev(fm.rt[x]);
}
inline void Link(int x,int y){
    mr(x);fm.f[x]=y;
}
inline void mt(int x,int y){
    mr(x);Access(y);fm.Splay(y);vl.Splay(fm.rt[y]);
}
int main(){
    Read(n);Read(m);Read(x);
    vl.mi[0]=2147483647;vl.ma[0]=-2147483647;
    for(i=1;i<=n;i++)fm.b[i]=vl.b[i]=fm.s[i]=vl.s[i]=1,fm.rt[i]=i;
    for(i=1;i<n;i++)Read(x),Read(y),Link(x,y);
    while(m--){
        Read(s);Read(x);Read(y);
        mt(x,y);
        if(s[0]=='I'&&s[2]=='c')Read(z),vl.Update_add(fm.rt[y],z);else
        if(s[0]=='S')printf("%lld\n",vl.sum[fm.rt[y]]);else
        if(s[0]=='I'&&s[2]=='v')vl.Update_rev(fm.rt[y]);else
        if(s[1]=='a')printf("%d\n",vl.ma[fm.rt[y]]);else printf("%d\n",vl.mi[fm.rt[y]]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值