To_Heart—题解——COCI 2014/2015 #3 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操作表示两个堆栈的相同的数的个数。

样例

样例输入

5
a 0
a 1
b 2
c 2 3
b 4

样例输出

2
1
2

题解

对于a类操作,我们可以把i看成是x延伸出去的一个儿子;
对于b类操作,我们可以发现i和x的父节点是等价的,所以我们直接将其在树上的节点设为x的父节点。
对于c类操作,因为每次加入栈中的数互不相同(所有的i都不同),所以只有在树上经过同一个操作的结点才会增加一个相等的数,即是找LCA。

代码

#include 
using namespace std;
const int Step = 20;

int n;
int tree[300005];
bool f[300005];
int pre[300005];
int dp[300005][30];
int tot[300005];
int First[300005];

int LCA(int x, int y) {
    if (pre[x] > pre[y]) {
        int t = x;
        x = y;
        y = t;
    }
    for (int i = Step; i >= 0; --i) {
        if (pre[dp[y][i]] >= pre[x])
            y = dp[y][i];
    }
    if (x == y)
        return x;
    for (int i = Step; i >= 0; --i) {
        if (dp[x][i] != dp[y][i]) {
            x = dp[x][i];
            y = dp[y][i];
        }
    }
    return dp[x][0];
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        char s[5];
        int x;
        scanf("%s%d", s, &x);
        // printf("\n%c\n%d\n",s[0],x);
        x = tree[x];
        if (s[0] == 'a') {
            tree[i] = i;
            dp[i][0] = x;
            tot[i] = tot[x] + 1;
            First[i] = i;
            pre[i] = pre[dp[i][0]] + 1;
            for (int j = 1; j <= Step; j++) {
                dp[i][j] = dp[dp[i][j - 1]][j - 1];
            }
        } else if (s[0] == 'b') {
            tree[i] = dp[x][0];
            printf("%d\n", First[x]);
        } else {
            int y;
            scanf("%d", &y);
            y = tree[y];
            printf("%d\n", tot[LCA(x, y)]);
            tree[i] = x;
        }
    }
    return 0;
}

你可能感兴趣的:(LCA)