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
#include
#include
#include
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]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);
        }
    }
}

你可能感兴趣的:(总结)