题目描述
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;
}