bzoj 2049 [Sdoi2008]Cave 洞穴勘测
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2049
第一道LCT!
很久才明白为什么要reverse。因为makeroot的splay是在原树上做的,所以深度真的改变,而且恰好符合reverse。
简洁的模板:https://blog.csdn.net/yxuanwkeith/article/details/50991326
学习论文:https://wenku.baidu.com/view/75906f160b4e767f5acfcedb.html
特别奇怪的是第37行为什么导致RE?
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1e4+5; int n,m,pre[N],c[N][2],rev[N],stack[N],top; int rdn() { int ret=0,fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=-1;ch=getchar();} while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar(); return ret*fx; } bool isroot(int x) { return c[pre[x]][0]!=x&&c[pre[x]][1]!=x; } void reverse(int x) { if(rev[x]){ rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][0],c[x][1]); rev[x]=0; } } void rotate(int x) { int y=pre[x],z=pre[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x; pre[x]=z;pre[y]=x; c[y][d]=c[x][!d];pre[c[x][!d]]=y;c[x][!d]=y; } void splay(int x) { stack[top=1]=x; //含x for(int t=x;!isroot(t);t=pre[t])stack[++top]=pre[t]; //含根 // for(int i=1;i<=top;i++)reverse(stack[i]); //为什么这行会导致RE? for(;top;top--)reverse(stack[top]);// for(;!isroot(x);rotate(x)) { int y=pre[x],z=pre[y]; if(isroot(y))continue; ((c[z][0]==y)^(c[y][0]==x))?rotate(x):rotate(y); } } void access(int x) { for(int t=0;x;c[x][1]=t,t=x,x=pre[x])splay(x); //条件是x,不是isroot(x),因为是在原树上弄 } void makeroot(int x) { access(x);splay(x);rev[x]^=1;//rev,因为是在原树上splay,故深度改变。正好符合reverse } void link(int x,int y) { makeroot(x);pre[x]=y; } void cut(int x,int y) { makeroot(x);access(y);splay(y); c[y][0]=0;pre[x]=0; } int find(int x) //找所在原树的根 { access(x);splay(x);int t; for(t=x;c[t][0];t=c[t][0]); return t; } int main() { char ch[10];int x,y; n=rdn();m=rdn(); for(int i=1;i<=m;i++) { scanf("%s",ch);x=rdn();y=rdn(); if(ch[0]=='C')link(x,y); if(ch[0]=='D')cut(x,y); if(ch[0]=='Q') if(find(x)==find(y))printf("Yes\n"); else printf("No\n"); } return 0; }