• 「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;
    		}
    	}
    }
    
  • 相关阅读:
    C语言笔记
    js学习笔记
    Javascript学习笔记
    Java基础知识
    使用 StackExchange.Redis 封装属于自己的 RedisHelper
    StackExchange.Redis 使用资料
    .NET平台下Redis使用(三)【ServiceStack.Redis学习】
    .NET平台下Redis使用(二)【StackExchange.Redis学习】
    Redis 详解 (一) StackExchange.Redis Client
    .NET中使用Redis
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12813775.html
Copyright © 2020-2023  润新知