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; }