堆栈游戏题解

    科技2022-08-15  89

    目录

    题目大意题目描述输入格式输出格式:样例样例输入样例输出 题解代码

    题目大意

    题目描述

    Mirko在玩堆栈游戏。开始他有一个空的堆栈,编号为0.在第i步(1<=i<=300000),他会选择一个编号为v的堆栈,复制一份并做如下操作:

    a v 表示将v号堆栈复制一份,新栈的编号为i,并将元素i压入新栈的栈顶。b v 表示将v号堆栈复制一份,新栈的编号为i,将新栈的栈顶元素弹出。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 <bits/stdc++.h> 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; }
    Processed: 0.010, SQL: 8