Description
Hint
(1le N, Mle 10^5)
Solution
我们将 (n) 个位置以及弹出看作 (n + 1) 个点,将弹力视作连边。
考虑 Link-Cut Tree。
操作 0 a b
:cut
原来的连边,link
新边。
操作 1 a
:split(a, n + 1)
,然后跳的次数就是 size[n + 1] - 1
。
但是最后的位置怎么求?这个简单,只要在 splay
上找前驱即可。由于 split
过了,所以根就是 (n + 1)。
当然,也可以通过求链上最大值来完成,但注意不要将 (n + 1) 也算进去了。
Code
求前驱用了第一种方法。
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : Codeforces 13E Holes
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
int ch[N][2], fa[N], size[N];
bool rev[N];
#define lc ch[x][0]
#define rc ch[x][1]
inline void pushup(int x) {
size[x] = size[lc] + size[rc] + 1;
}
inline void setRev(int x) {
swap(lc, rc), rev[x] ^= 1;
}
inline void pushdown(int x) {
if (rev[x]) {
if (lc) setRev(lc);
if (rc) setRev(rc);
rev[x] = 0;
}
}
inline bool isRoot(int x) {
return x != ch[fa[x]][0] && x != ch[fa[x]][1];
}
inline int getc(int x) {
return x == ch[fa[x]][1];
}
inline void rotate(int x) {
int y = fa[x], z = fa[y];
int k = getc(x), w = ch[x][!k];
if (!isRoot(y)) ch[z][getc(y)] = x;
ch[x][!k] = y, ch[y][k] = w;
if (w) fa[w] = y;
fa[y] = x, fa[x] = z, pushup(y);
}
inline void pushdownAll(int x) {
if (!isRoot(x)) pushdownAll(fa[x]);
pushdown(x);
}
inline void splay(int x) {
pushdownAll(x);
for (register int y = fa[x]; !isRoot(x); rotate(x), y = fa[x])
if (!isRoot(y)) rotate(getc(x) != getc(y) ? x : y);
pushup(x);
}
inline void access(int x) {
for (register int y = 0; x; x = fa[y = x])
splay(x), rc = y, pushup(x);
}
inline void makeRoot(int x) {
access(x), splay(x), setRev(x);
}
inline void split(int x, int y) {
makeRoot(x), access(y), splay(y);
}
inline int findRoot(int x) {
access(x), splay(x), pushdown(x);
while (lc) pushdown(x = lc);
return splay(x), x;
}
inline void link(int x, int y) {
if (makeRoot(x), findRoot(y) != x) fa[x] = y;
}
inline void cut(int x, int y) {
makeRoot(x);
if (findRoot(y) == x && fa[y] == x && !ch[y][0])
fa[y] = rc = 0, pushup(x);
}
int n, q;
inline int getPre() {
int x = ch[n + 1][0];
while (pushdown(x), rc) x = rc;
return x;
}
int nxt[N];
signed main() {
ios::sync_with_stdio(false);
cin >> n >> q;
for (register int i = 1; i <= n + 1; i++)
size[i] = 1;
for (register int x, i = 1; i <= n; i++) {
cin >> nxt[i], x = nxt[i];
if (i + x <= n) link(i, i + x);
else link(i, n + 1);
}
for (; q; --q) {
int cmd, pos, val;
cin >> cmd >> pos;
if (cmd == 1) {
split(pos, n + 1);
cout << getPre() << ' ';
cout << size[n + 1] - 1 << endl;
} else {
cin >> val;
cut(pos, pos + nxt[pos] <= n ? pos + nxt[pos] : n + 1);
link(pos, pos + val <= n ? pos + val : n + 1);
nxt[pos] = val;
}
}
}