COCI CONTEST #3 29.11.2014 T5 STOGOVI

第五题:
题目描述
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操作表示两个堆栈的相同的数的个数。
其实就是一个lca
a x就是在x后面增加一个儿子,节点编号是i
b x就是输出find(x),然后unite(i,f[x])->并查集
c x y就是输出lca(find(x),find(y)),然后unite(i,x)
注意lca是求的祖先在树中的深度,深度的维护在a x那儿,增加儿子,儿子的深度是爸爸的深度+1
A了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int fa[300010][20],f[300010],dep[300010],cnt,n;
int find(int x)
{
    return (x==f[x])?x:f[x]=find(f[x]);
}
inline void unite(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)f[fx]=fy;
}
inline void adjust(int &u,int val)
{
    for(int j=19;j>=0;--j)
        if(dep[fa[u][j]]>=val)
            u=fa[u][j];
}
inline int lca(int u,int v)
{
    if(dep[u]>dep[v])adjust(u,dep[v]);
    else if(dep[u]<dep[v])adjust(v,dep[u]);
    if(u==v)return dep[u];
    for(int j=19;j>=0;--j)
        if(fa[u][j]!=fa[v][j])
            u=fa[u][j],v=fa[v][j];
    return dep[fa[u][0]];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        f[i]=i;
    for(int i=1;i<=n;++i)
    {
        char op[3];
        int u,v;
        scanf("%s",op);
        if(op[0]=='a')
        {
            scanf("%d",&u);
            u=find(u);
            fa[i][0]=u;
            dep[i]=dep[u]+1;
            for(int j=1;j<20&&fa[i][j-1];j++)
                fa[i][j]=fa[fa[i][j-1]][j-1];
        }
        else if(op[0]=='b')
        {
            scanf("%d",&u);
            u=find(u);
            printf("%d\n",u);
            unite(i,fa[u][0]);
        }
        else if(op[0]=='c')
        {
            scanf("%d%d",&u,&v);
            u=find(u);
            v=find(v);
            printf("%d\n",lca(u,v));
            unite(i,u);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值