题意:一开始给定n个盒子的摆的嵌套关系。有两种操作,1.MOVE x y:把编号x的箱子及其包含的箱子放进编号为y的箱子;
2.QUERY x :查询编号x的箱子所在的最靠外的箱子。
方法一:splay+括号序
思路:将全部的树逐个dfs,这样对于每一棵树都可以得到一个括号序列,对于MOVE操作,我们将那个根所在的左右括号的一整段
取出,连接到新的结点的左括号右边,这么做我们可以保证得到的一定也是一个括号序列。我们将x和x+n分别旋根,这样我们可以得到一个x和x+n,x+n是根,x是其左子树的某一个结点,这样x的左子树和x+n的右子树是无效的,我们剪掉它们,并且将x+n的右子树接到x的左子树最后,接着把x+n旋根,保证平衡性。对于QUERY操作,我们直接去找其结点所在的括号序列靠最左边的是谁就可以了。详见代码:
/********************************************************* file name: hdu2475.cpp author : kereo create time: 2015年02月18日 星期三 14时29分43秒 *********************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int sigma_size=26; const int N=100+50; const int MAXN=100000+50; const int inf=0x3fffffff; const double eps=1e-8; const int mod=1000000000+7; #define L(x) (x->ch[0]) #define R(x) (x->ch[1]) #define PII pair<int, int> #define mk(x,y) make_pair((x),(y)) int n,m,edge_cnt,cnt; char str[N]; int head[MAXN],seq[MAXN],vis[MAXN]; struct Edge{ int v,next; }edge[MAXN]; struct node{ node *fa,*ch[2]; }nod[MAXN],*root,*null; struct Splay{ void rotate(node *x,int d){ node *y=x->fa; //push_down(y); push_down(x); y->ch[d^1]=x->ch[d]; if(x->ch[d]!=null) x->ch[d]->fa=y; x->fa=y->fa; if(y->fa!=null){ int d=y->fa->ch[0] == y ? 0 : 1; y->fa->ch[d]=x; } y->fa=x; x->ch[d]=y; //push_up(y); } void splay(node *x,node *fa){ while(x->fa!=fa){ //push_down(x); node *y=x->fa; if(y->fa == fa){ int d=y->ch[0] == x ? 1 : 0; rotate(x,d); } else{ int d=y->fa->ch[0] == y ? 1 : 0; if(y->ch[d] == x){ rotate(x,d^1); rotate(x,d); } else{ rotate(y,d); rotate(x,d); } } } //push_up(x); if(fa == null) root=x; } void newnode(node *&x,node *fa,int pos){ x=&nod[pos]; x->fa=fa; L(x)=R(x)=null; } void build(node *&rt,node *fa,int l,int r){ if(l>r) return ; int mid=(l+r)>>1; newnode(rt,fa,seq[mid]); build(L(rt),rt,l,mid-1); build(R(rt),rt,mid+1,r); //push_up(rt); } void init(){ null=&nod[0]; root=null; L(null)=R(null)=null->fa=null; } void MOVE(int x,int y){ if(x == y) return ; splay(&nod[x],null); splay(&nod[x+n],&nod[x]); node *tmp; for(tmp=&nod[y];tmp!=null;tmp=tmp->fa){ if((&nod[x+n])->ch[0] == tmp) return ; } node *pre=(&nod[x])->ch[0],*suf=(&nod[x+n])->ch[1]; (&nod[x])->ch[0]=(&nod[x+n])->ch[1]=pre->fa=suf->fa=null; if(pre!=null && suf!=null){ while(L(suf)!=null) suf=L(suf); pre->fa=suf; L(suf)=pre; } if(y == 0) return ; splay(&nod[y],null); for(tmp=(&nod[y])->ch[1];L(tmp)!=null;tmp=L(tmp)) ; splay(tmp,&nod[y]); L(tmp)=&nod[x]; (&nod[x])->fa=tmp; } int QUERY(int x){ node *tmp=&nod[x]; splay(tmp,null); for(;L(tmp)!=null;tmp=L(tmp)) ; return tmp-nod; } }spt; void init(){ edge_cnt=0; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); } void addedge(int u,int v){ edge[edge_cnt].v=v; edge[edge_cnt].next=head[u]; head[u]=edge_cnt++; } void dfs(int u){ seq[++cnt]=u; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; dfs(v); } seq[++cnt]=u+n; } int main(){ int flag=1; //freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ init(); spt.init(); if(flag) flag=0; else printf("\n"); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); if(x == 0) vis[i]=1; else addedge(x,i); } for(int i=1;i<=n;i++){ if(!vis[i]) continue; cnt=0; dfs(i); spt.build(root,null,1,cnt); } scanf("%d",&m); while(m--){ scanf("%s",str); if(strcmp(str,"MOVE") == 0){ int x,y; scanf("%d%d",&x,&y); spt.MOVE(x,y); } else if(strcmp(str,"QUERY") == 0){ int x; scanf("%d",&x); int ans=spt.QUERY(x); printf("%d\n",ans); } } } return 0; }
方法二:Link-Cut Tree
思路:参阅《QTREE的一些研究》。tip:注释掉的部分导致TLE的原因:y=x->fa,恰好根是y->fa,且x,y,y->fa为“一字型”,那么会先把根
转下去,那么更新x->par的时候就会出现问题。详见代码:
/********************************************************* file name: hdu2475.cpp author : kereo create time: 2015年02月21日 星期六 10时23分07秒 *********************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int sigma_size=26; const int N=100+50; const int MAXN=100000+50; const int inf=0x3fffffff; const double eps=1e-8; const int mod=1000000000+7; #define L(x) (x->ch[0]) #define R(x) (x->ch[1]) #define PII pair<int, int> #define mk(x,y) make_pair((x),(y)) int n,m; char str[N]; struct node{ node *ch[2],*par,*fa; }nod[MAXN],*null,*root; struct LCT{ void rotate(node *x,int d){ node *y=x->fa; //push_down(y); push_down(x); y->ch[d^1]=x->ch[d]; x->ch[d]->fa=y; x->fa=y->fa; if(y->fa!=null){ int d=y->fa->ch[0] == y ? 0 : 1; y->fa->ch[d]=x; } y->fa=x; x->ch[d]=y; //push_up(y); } /*void splay(node *x,node *fa){ while(x->fa!=fa){ node *y=x->fa; if(y->fa == fa){ x->par=y->par; y->par=null; int d=y->ch[0] == x ? 1 : 0; rotate(x,d); } else{ int d=y->fa->ch[0] == y ? 1 : 0; if(y->ch[d] == x){ rotate(x,d^1); rotate(x,d); } else{ rotate(y,d); rotate(x,d); } } } if(fa == null) root=x; }*/ node* findroot(node *x){ while(x->fa!=null) x=x->fa; return x; } void splay(node *x,node *fa){ node *tmp=findroot(x); if(x == tmp) return ; x->par=tmp->par; tmp->par=null; while(x->fa!=fa){ node *y=x->fa; if(y->fa == fa){ int d=y->ch[0] == x ? 1 : 0; rotate(x,d); } else{ int d=y->fa->ch[0] == y ? 1 : 0; if(y->ch[d] == x){ rotate(x,d^1); rotate(x,d); } else{ rotate(y,d); rotate(x,d); } } } } void Access(node *x){ node *tmp=null; while(x!=null){ splay(x,null); if(R(x)!=null){ R(x)->fa=null; R(x)->par=x; } R(x)=tmp; if(tmp!=null){ tmp->fa=x; tmp->par=null; } tmp=x; x=x->par; } } void Cut(node *x){ Access(x); splay(x,null); if(L(x)!=null){ L(x)->par=x->par; x->par=null; L(x)->fa=null; L(x)=null; } } void Link(node *x,node *y){ if(y == null) Cut(x); else{ Access(y); splay(y,null); node *tmp=findroot(x); if(tmp == y) return ; Cut(x); x->par=y; Access(x); } } void init(){ null=&nod[0]; root=null; L(root)=R(root)=root->fa=null; } void newnode(node *&x,node *fa,node *par,int pos){ x=&nod[pos]; x->fa=fa; x->par=par; L(x)=R(x)=null; } int query(node *x){ Access(x); splay(x,null); while(L(x)!=null) x=L(x); return x-nod; } }lct; int main(){ int flag=1; //freopen("in.txt","r",stdin); while(~scanf("%d",&n)){ if(flag) flag=0; else printf("\n"); lct.init(); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); lct.newnode(root,null,&nod[x],i); } //for(int i=1;i<=n;i++) // printf("i=%d par=%d fa=%d\n",i,(&nod[i])->par-nod,(&nod[i])->fa-nod); scanf("%d",&m); while(m--){ scanf("%s",str); if(strcmp(str,"MOVE") == 0){ int x,y; scanf("%d%d",&x,&y); lct.Link(&nod[x],&nod[y]); } else if(strcmp(str,"QUERY") == 0){ int x; scanf("%d",&x); int ans=lct.query(&nod[x]); printf("%d\n",ans); } } } return 0; }