bzoj3159: 决战

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3159

思路:题解与标程在此:http://tieba.baidu.com/p/2307619154

首先链翻转显然不能直接在lct上打翻转标记,那样是在翻转链的深度,不是翻转链上的值

于是就有了一种做法,写两个splay,一个维护权值,一个维护形态

每棵形态splay和对应值splay总保证点数相同,这样对于权值翻转我们就可以只在值splay上翻转,形态splay不变即可

关键是维护形态splay到值splay的指针

最重要的一点就是维护形态splay的根到对应值splay的根的指针

题解已经讲的比较清楚了,但是具体细节比较多

主要是在access的同时维护这个指针(因为access会导致splay的分离和合并,一定要想清楚)

形态splay执行splay操作时也要记得把原来根的指针传递给现在splay上来的新根

总之就是各种错,各种坑,改了不下十个错误才改对


另外我怎么觉得跨过LCA的链也是可以翻转的,这可是动态树啊,makeroot一下,access一下不就提出了这个链吗,代码不会有任何区别。也许是有不为人知的阴谋


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls ch[x][0]
#define rs ch[x][1]
const int maxn=100010,maxm=maxn<<1;
typedef long long ll;
using namespace std;
int n,R,cas,Q,pre[maxm],now[maxn],son[maxm],tot;char op[12];
void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
 
struct Tsplay{
    int siz[maxn],ch[maxn][2],fa[maxn],tag[maxn];ll mins[maxn],maxs[maxn],sum[maxn],val[maxn];bool rev[maxn];
    int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    int which(int x){return ch[fa[x]][1]==x;}
    void init(int x,int v){siz[x]=1,mins[x]=maxs[x]=sum[x]=val[x]=v;}
    void update(int x){
        siz[x]=1,mins[x]=maxs[x]=sum[x]=val[x];
        if (ls) siz[x]+=siz[ls],mins[x]=min(mins[x],mins[ls]),maxs[x]=max(maxs[x],maxs[ls]),sum[x]+=sum[ls];
        if (rs) siz[x]+=siz[rs],mins[x]=min(mins[x],mins[rs]),maxs[x]=max(maxs[x],maxs[rs]),sum[x]+=sum[rs];
    }
    void add(int x,int v){if (x) sum[x]+=1ll*v*siz[x],tag[x]+=v,mins[x]+=v,maxs[x]+=v,val[x]+=v;}
    void rever(int x){swap(ls,rs),rev[x]^=1;}
    void down(int x){
        if (tag[x]) add(ls,tag[x]),add(rs,tag[x]),tag[x]=0;
        if (rev[x]) rever(ls),rever(rs),rev[x]=0;
    }
    int relax(int x){
        int anc=isroot(x)?x:relax(fa[x]);
        down(x);return anc;
    }
    void rotate(int x){  
        int y=fa[x],z=fa[y],nx=which(x),ny=which(y);  
        fa[ch[x][!nx]]=y,ch[y][nx]=ch[x][!nx];  
        fa[x]=z;if (!isroot(y)) ch[z][ny]=x;//这行要放在下一行前,不然isroot会错
        fa[y]=x,ch[x][!nx]=y;update(y);
    }
    void splay(int x){
        relax(x);
        while(!isroot(x)){
            int y=fa[x];
            if (isroot(y)) rotate(x);
            else if (which(x)==which(y)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
        }
        update(x);
    }
    int findrt(int &x){while (fa[x]) x=fa[x];return x;}
    int find(int &x,int rank){
        for (;;){
        	down(x);
            if (rank<=siz[ls]) x=ls;
            else if (rank==siz[ls]+1) return x;
            else rank-=(siz[ls]+1),x=rs;
        }
    }
}val;

struct Tlct{
    int siz[maxn],ch[maxn][2],fa[maxn],rt[maxn],q[maxn];bool rev[maxn];
    int isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    int which(int x){return ch[fa[x]][1]==x;}
    void init(int x,int v,int ff){rt[x]=x,siz[x]=1,fa[x]=ff,val.init(x,v);}
    void update(int x){siz[x]=siz[ls]+siz[rs]+1;}
    void rever(int x){swap(ls,rs),rev[x]^=1;}
    void down(int x){if (rev[x]) rever(ls),rever(rs),rev[x]=0;}
	int relax(int x){
        int anc=isroot(x)?x:relax(fa[x]);
        down(x);return anc;
    }
    void rotate(int x){  
        int y=fa[x],z=fa[y],nx=which(x),ny=which(y);  
        fa[ch[x][!nx]]=y,ch[y][nx]=ch[x][!nx];  
        fa[x]=z;if (!isroot(y)) ch[z][ny]=x;  
        fa[y]=x,ch[x][!nx]=y;update(y);  
    }
    void splay(int x){
    	int anc=relax(x);
        rt[x]=rt[anc];
        while(!isroot(x)){
            int y=fa[x];
            if (isroot(y)) rotate(x);
            else if (which(x)==which(y)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
        }
        update(x);
    }
    void access(int x){
        for (int y=0;x;y=x,x=fa[x]){
            splay(x);int x2=val.findrt(rt[x]);int y2=val.findrt(rt[y]);
            if (!y) y2=0;//这句特判一定要加,因为rt【0】会被改动
            val.find(x2,siz[ls]+1),val.splay(x2),rt[x]=x2;
            rt[rs]=val.ch[x2][1],val.fa[val.ch[x2][1]]=0,val.ch[x2][1]=y2,val.fa[y2]=x2,val.update(x2);
            rs=y,update(x);
        }
    }
    void makeroot(int x){access(x),splay(x),rever(x),val.rever(rt[x]);}
    void split(int x,int y){makeroot(x),access(y);}
    void dfs(int x,int ff){
        init(x,0,ff);
        for (int y=now[x];y;y=pre[y])
            if (son[y]!=ff) dfs(son[y],x);
    }
}lct;

int main(){
    scanf("%d%d%d",&n,&Q,&R);
    for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    lct.dfs(R,0);
    for (int i=1,x,y,z;i<=Q;i++){
        scanf("%s%d%d",op+1,&x,&y);
        lct.split(x,y);int vy=val.findrt(lct.rt[y]);//SB错误,y打成x
        if (op[3]=='c') scanf("%d",&z),val.add(vy,z);
        else if (op[3]=='m') printf("%lld\n",val.sum[vy]);
        else if (op[3]=='j') printf("%lld\n",val.maxs[vy]);
        else if (op[3]=='n') printf("%lld\n",val.mins[vy]);
        else val.rever(vy);
    }
    return 0;
}



你可能感兴趣的:(Access)