Solution [COCI 2014/2015 #3]STOGOVI
题目大意:维护一个可持久化栈,支持(push),(pop),以及比较两个版本栈相同元素个数。注意:(push)操作仅会(push)当前操作编号进栈。
可持久化数据结构
分析:
暴力做法,(bitset),期望得分(0)(没有写,开小点应该有点分数)
暴力做法的优化,可持久化权值线段树,每次比较相同元素个数,如果走到同一个节点就剪枝,在loj上面获得了53pts
继续可持久化的思路,我也不知道我为啥当时想不开拿权值线段树去维护一个栈,我们把栈表示成一条链
由于一个点如果被(pop)出去之后就不可能再被(push)进来了,所以两个栈元素交集一定是两个栈的公共前缀。两条链的公共前缀,和( ext{LCA})比较相似,因此我们在树上完成这个问题。
(push)操作,直接新建一个点。(pop)操作,跳到它的父亲。比较操作,找到两个版本的链的结尾节点,取( ext{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
",pos[v]),pos[i] = faz[pos[v]][0];
else if(com[0] == 'c')scanf("%d",&w),pos[i] = pos[v],printf("%d
",dep[lca(pos[v],pos[w])] - 1);
}
return 0;
}