堆栈游戏

题目描述

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;
} 
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值