「Codeforces 13E」Holes

Description

JXPwqO.png

Hint

(1le N, Mle 10^5)

Solution

我们将 (n) 个位置以及弹出看作 (n + 1) 个点,将弹力视作连边。

考虑 Link-Cut Tree。

操作 0 a bcut 原来的连边,link 新边。

操作 1 asplit(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;
		}
	}
}
原文地址:https://www.cnblogs.com/-Wallace-/p/12813775.html