Mirko在玩堆栈游戏。开始他有一个空的堆栈,编号为0.在第i步(1<=i<=300000),他会选择一个编号为v的堆栈,复制一份并做如下操作: 1.a v 表示将v号堆栈复制一份,新栈的编号为i,并将元素i压入新栈的栈顶。 2. b v 表示将v号堆栈复制一份,新栈的编号为i,将新栈的栈顶元素弹出。 3.c v w 将v号堆栈复制一份,编号为i,并比较第v号和第w号堆栈中有多少相同的数。
输入格式:第一行一个整数n,表示有n步。 接下来n步,每步表示一个操作,如上所述。 输出格式
对所有的b操作和c操作,输出结果,每行一个。b操作需要输出该栈移除的元素,c操作表示两个堆栈的相同的数的个数。
5 a 0 a 1 b 2 c 2 3 b 4
2 1 2
a数组存的是该点的栈顶元素 t数组是树上的点 d数组是深度 当a操作时,新建一点,连接V点 当b操作时,新建一点,成为其父亲,与其原来父亲重合,输出a[t[v]] 当c操作时,这是我们发现i号栈内的元素就为从父亲节点到到i号点的路径上的点,所以输出两点的LCA的深度就行了,再新建一点,并将新建一点与v点重合
#include<bits/stdc++.h> using namespace std; int a[300005],s,t[300005],d[300005],f[300005][105],cnt=0,n,m,T; queue<int>q; int lca(int x,int y){ if(d[x]>d[y])swap(x,y); for(int i=20;i>=0;i--){ if(d[f[y][i]]>=d[x]){ y=f[y][i]; } } if(x==y){ return x; } for(int i=20;i>=0;i--){ if(f[x][i]!=f[y][i]){ x=f[x][i]; y=f[y][i]; } } return f[y][0]; } int main(){ scanf("%d",&n); memset(d,0,sizeof d); cnt=0; for(int i=1,v,w;i<=n;i++){ char u; scanf("\n%c ",&u); if(u=='a'){ scanf("%d",&v); t[i]=i; f[i][0]=t[v]; a[i]=i; d[i]=d[f[i][0]]+1; for(int j=1;j<=20;j++){ f[i][j]=f[f[i][j-1]][j-1]; } }else if(u=='b'){ scanf("%d",&v); t[i]=f[t[v]][0]; printf("%d\n",a[t[v]]); }else if(u=='c'){ scanf("%d%d",&v,&w); printf("%d\n",d[lca(t[v],t[w])]); t[i]=t[v]; } } return 0; }