题目链接

题目大意:维护一个可持久化栈,支持\(push\)\(pop\),以及比较两个版本栈相同元素个数。注意:\(push\)操作仅会\(push\)当前操作编号进栈。

可持久化数据结构


分析:

暴力做法,\(bitset\),期望得分\(0\)(没有写,开小点应该有点分数)

暴力做法的优化,可持久化权值线段树,每次比较相同元素个数,如果走到同一个节点就剪枝,在loj上面获得了53pts

继续可持久化的思路,我也不知道我为啥当时想不开拿权值线段树去维护一个栈,我们把栈表示成一条链

由于一个点如果被\(pop\)出去之后就不可能再被\(push\)进来了,所以两个栈元素交集一定是两个栈的公共前缀。两条链的公共前缀,和\(\text{LCA}\)比较相似,因此我们在树上完成这个问题。

\(push\)操作,直接新建一个点。\(pop\)操作,跳到它的父亲。比较操作,找到两个版本的链的结尾节点,取\(\text{LCA}\)的深度就是答案。

倍增可以维护

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 100,maxdep = 25;
vector<int> G[maxn];
int faz[maxn][maxdep + 1],dep[maxn],pos[maxn],tot,n;
inline void addedge(int from,int to){
	G[from].push_back(to);
	dep[to] = dep[from] + 1;
	faz[to][0] = from;
	for(int i = 1;i <= maxdep;i++)faz[to][i] = faz[faz[to][i - 1]][i - 1];
}
inline int lca(int x,int y){
	if(dep[x] < dep[y])swap(x,y);
	for(int i = maxdep;i >= 0;i--)
		if(dep[faz[x][i]] >= dep[y])x = faz[x][i];
	if(x == y)return x;
	for(int i = maxdep;i >= 0;i--)
		if(faz[x][i] != faz[y][i])x = faz[x][i],y = faz[y][i];
	return faz[x][0];
}
char com[4];
int main(){
	scanf("%d",&n);
	dep[0] = 1;
	for(int v,w,i = 1;i <= n;i++){
		scanf("%s %d",com,&v);
		if(com[0] == 'a')addedge(pos[v],i),pos[i] = i;
		else if(com[0] == 'b')printf("%d\n",pos[v]),pos[i] = faz[pos[v]][0];
		else if(com[0] == 'c')scanf("%d",&w),pos[i] = pos[v],printf("%d\n",dep[lca(pos[v],pos[w])] - 1);
	}
	return 0;
}

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-07
  • 2022-12-23
  • 2022-12-23
  • 2018-11-21
  • 2021-10-30
猜你喜欢
  • 2022-12-23
  • 2021-05-11
  • 2022-12-23
  • 2021-05-21
  • 2021-07-21
  • 2021-12-04
  • 2022-12-23
相关资源
相似解决方案