搞了这么长时间Splay终于可以搞LCT了,等等,什么是LCT?
$LCT$就是$Link-Cut-Tree$,是维护动态树的一个很高效的数据结构,每次修改和查询的均摊复杂度为$O(logN)$,因为那是用splay维护的,所以时间常数也会比较大..
但是相信有节操的出题人是不会恶意卡$LCT$的!
LCT的具体说明就就那篇喜闻乐见的Qtree研究,虽然我并没有怎么看懂,也许是我太弱了吧,总之和啃别人随手打的博客而言,那篇论文还是相对系统的了。
一句话概括$Link-Cut-Tree$就是Link-Cut-Tree=splay+树剖,所以下面的一些简要介绍沿用树剖和splay的用语。
具体说明几个操作;
0.$Splay$
和普通splay几乎一样,但是有一点需要注意,写在注释里了。
inline bool isroot(int node){ if(t[node].fa==0)return 1; return t[t[node].fa].son[0]!=node&&t[t[node].fa].son[1]!=node; } inline int get(int node){return t[t[node].fa].son[1]==node;} void rotate(int node){ int old=t[node].fa,oldf=t[old].fa,which=get(node); if(!isroot(old))t[oldf].son[t[oldf].son[1]==old]=node;//先判断old是不是根再实现翻转,因为先翻转后无论如何old一定不是根 t[old].son[which]=t[node].son[which^1];t[t[old].son[which]].fa=old; t[node].son[which^1]=old;t[old].fa=node;t[node].fa=oldf; } void splay(int x){ int top=0;q[++top]=x; for(int i=x;!isroot(i);i=t[i].fa)q[++top]=t[i].fa; for(int i=top;i;i--)downit(q[i]); while(!isroot(x)){ int old=t[x].fa,oldf=t[old].fa; if(!isroot(old))rotate(get(x)==get(old)?old:x); rotate(x); } }
1.$Access$
这个操作就是把当前节点到当前树根变为重链。
具体实现的话和树剖其实有点像,跳到一条链的根,对链操作,跳掉下一条链的底。
void access(int node){ int tmp=0; while(node){ splay(node);t[node].son[1]=tmp; tmp=node;node=t[node].fa; } }
2.$Reverse$
具体的作用就是把一个节点转到根,和splay实现区间翻转挺像的,代码实现不难理解。
void Reverse(int node){access(node);splay(node);t[node].tag^=1;}
3.$Link$
首先把一个节点转到树根,然后由这个节点向另一节点连条虚边,然后splay一下。
void Link(int noda,int nodb){ Reverse(noda); t[noda].fa=nodb; splay(noda); }
4.$Cut$
和上一个差不多。
void Cut(int noda,int nodb){Reverse(noda);access(nodb);splay(nodb);t[nodb].son[0]=t[noda].fa=0;}
5.$find$
int find(int node){ access(node);splay(node); int tmp=node; while(t[tmp].son[0])tmp=t[tmp].son[0]; return tmp; }
6.$LCA$
void LCA(int noda,int nodb){//noda is LCA Reverse(nodb);access(noda);splay(noda); }
这些操作拼接起来就是这道题的实现了。
//BZOJ 2049 //by Cydiater //2016.9.12 #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <map> #include <ctime> #include <cmath> #include <cstdlib> #include <iomanip> #include <algorithm> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) #define FILE "sdoi2008_cave" const int MAXN=1e6+5; const int oo=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int q[MAXN],top=0,head,tail,N,M,noda,nodb; char s[15]; struct Splay{ int son[2],fa,tag,siz; }t[MAXN]; namespace solution{ inline bool isroot(int node){ if(t[node].fa==0)return 1; return t[t[node].fa].son[0]!=node&&t[t[node].fa].son[1]!=node; } inline int get(int node){return t[t[node].fa].son[1]==node;} inline void downit(int node){ if(t[node].tag){ int leftson=t[node].son[0],rightson=t[node].son[1]; t[leftson].tag^=1;t[rightson].tag^=1; swap(t[node].son[0],t[node].son[1]); t[node].tag=0; } } void rotate(int node){ int old=t[node].fa,oldf=t[old].fa,which=get(node); if(!isroot(old))t[oldf].son[t[oldf].son[1]==old]=node;//先判断old是不是根再实现翻转,因为先翻转后无论如何old一定不是根 t[old].son[which]=t[node].son[which^1];t[t[old].son[which]].fa=old; t[node].son[which^1]=old;t[old].fa=node;t[node].fa=oldf; } void splay(int x){ int top=0;q[++top]=x; for(int i=x;!isroot(i);i=t[i].fa)q[++top]=t[i].fa; for(int i=top;i;i--)downit(q[i]); while(!isroot(x)){ int old=t[x].fa,oldf=t[old].fa; if(!isroot(old))rotate(get(x)==get(old)?old:x); rotate(x); } } void access(int node){ int tmp=0; while(node){ splay(node);t[node].son[1]=tmp; tmp=node;node=t[node].fa; } } void Reverse(int node){access(node);splay(node);t[node].tag^=1;} void Link(int noda,int nodb){ Reverse(noda); t[noda].fa=nodb; splay(noda); } void Cut(int noda,int nodb){Reverse(noda);access(nodb);splay(nodb);t[nodb].son[0]=t[noda].fa=0;} int find(int node){ access(node);splay(node); int tmp=node; while(t[tmp].son[0])tmp=t[tmp].son[0]; return tmp; } } int main(){ //freopen(FILE".in","r",stdin); //freopen(FILE".out","w",stdout); freopen("input.in","r",stdin); using namespace solution; N=read();M=read(); while(M--){ scanf("%s",s);noda=read();nodb=read(); if(s[0]=='C')Link(noda,nodb); if(s[0]=='D')Cut(noda,nodb); if(s[0]=='Q')puts(find(noda)==find(nodb)?"Yes":"No"); } return 0; }