• UOJ207 共价大爷游长沙


    题目蓝链

    Description

    给你一个(n)个点的树,你需要支持(m)个以下(4)种操作:

    1. 删除树中的一条边,并且再连接一条边,满足操作之后仍然一棵树

    2. 往集合中加入一条路径

    3. 删去第(x)次往集合里加入的路径

    4. 询问树上的一条边是否被集合中所有的路径经过

    (n leq 10^5, m leq 3 cdot 10^5)

    Solution

    对于操作(4),如果我们暴力的去查询集合中所有路径,那显然是不现实的。我们可以考虑每次插入一条路径后,把路径的两个端点都异或上同一个随机值

    那么我们在查询的时候,就只需要查询在断掉查询边后的两棵子树中,任选其一查询其子树异或和是否等于当前集合里所有路径随机值的异或和就可以了。如果相等就说明当前集合里的所有路径都经过了查询边

    至于断边连边以及子树查询操作,就可以利用LCT来实现

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define fst first
    #define snd second
    #define mp make_pair
    #define squ(x) ((LL)(x) * (x))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    
    typedef long long LL;
    typedef pair<int, int> pii;
    
    template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
    
    inline int read() {
    	int sum = 0, fg = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    	return fg * sum;
    }
    
    typedef unsigned long long ULL;
    
    static random_device rd;
    
    inline ULL get_rand() { return ((ULL) rd() << 32) | rd(); }
    
    const int maxn = 1e5 + 10;
    const int maxm = 3e5 + 10;
    
    namespace LCT {
    	struct node {
    		bool rev;
    		int son[2], f;
    		ULL v, s, x;
    	}A[maxn];
    #define ls(x) A[x].son[0]
    #define rs(x) A[x].son[1]
    #define fa(x) A[x].f
    
    	inline void push_up(int x) { A[x].s = A[x].v ^ A[x].x ^ A[ls(x)].s ^ A[rs(x)].s; } /**/
    	inline void push_down(int x) {
    		if (A[x].rev) {
    			swap(ls(x), rs(x));
    			A[ls(x)].rev ^= 1, A[rs(x)].rev ^= 1, A[x].rev = 0;
    		}
    	}
    
    	inline bool chkrt(int x) { return x != ls(fa(x)) && x != rs(fa(x)); }
    	inline bool chk(int x) { return x == rs(fa(x)); }
    	inline void link(int x, int y, int f) { fa(x) = y, A[y].son[f] = x; }
    	inline void rotate(int x) {
    		int f = fa(x), dx = chk(x), df = chk(f);
    		link(A[x].son[dx ^ 1], f, dx);
    		if (!chkrt(f)) link(x, fa(f), df); else fa(x) = fa(f);
    		link(f, x, dx ^ 1);
    		push_up(f), push_up(x);
    	}
    	inline void splay(int x) {
    		static int S[maxn]; S[++S[0]] = x;
    		for (int y = x; !chkrt(y); y = fa(y)) S[++S[0]] = fa(y);
    		while (S[0]) push_down(S[S[0]--]);
    		while (!chkrt(x)) { if (!chkrt(fa(x))) rotate(chk(x) == chk(fa(x)) ? fa(x) : x); rotate(x); }
    	}
    
    	inline void access(int x) { int _x = x; for (int lst = 0; x; x = fa(lst = x)) splay(x), A[x].x ^= A[rs(x)].s ^ A[lst].s, rs(x) = lst, push_up(x); splay(_x); }
    	inline void mkrt(int x) { access(x), A[x].rev ^= 1, push_down(x); }
    	inline int getrt(int x) { access(x); while (ls(x)) push_down(x = ls(x)); return x; }
    	inline void split(int x, int y) { mkrt(x), access(y); }
    	inline void Link(int x, int y) { mkrt(x), access(y); fa(x) = y, A[y].x ^= A[x].s; }
    	inline void Cut(int x, int y) { split(x, y), fa(x) = 0, ls(y) = 0, push_up(y); }
    
    	inline void modify(int x, ULL v) { mkrt(x), A[x].v ^= v, push_up(x); }
    	inline ULL query(int x) { access(x); return A[x].v ^ A[x].x; }
    }
    
    ULL w[maxm], Sum;
    int X[maxm], Y[maxm], cnt;
    
    int n, m;
    
    int main() {
    #ifdef xunzhen
    	freopen("travel.in", "r", stdin);
    	freopen("travel.out", "w", stdout);
    #endif
    
    	int ID = read();
    	n = read(), m = read();
    	for (int i = 1; i < n; i++) {
    		int x = read(), y = read();
    		LCT::Link(x, y);
    	}
    
    	for (int i = 1; i <= m; i++) {
    		int op = read();
    		if (op == 1) {
    			int x = read(), y = read();
    			LCT::Cut(x, y);
    			x = read(), y = read();
    			LCT::Link(x, y);
    		}
    		if (op == 2) {
    			int x = read(), y = read();
    			w[++cnt] = get_rand(), X[cnt] = x, Y[cnt] = y;
    			LCT::modify(x, w[cnt]), LCT::modify(y, w[cnt]);
    			Sum ^= w[cnt];
    		}
    		if (op == 3) {
    			int x = read();
    			LCT::modify(X[x], w[x]), LCT::modify(Y[x], w[x]);
    			Sum ^= w[x];
    		}
    		if (op == 4) {
    			int x = read(), y = read();
    			LCT::mkrt(y);
    			printf(LCT::query(x) == Sum ? "YES
    " : "NO
    ");
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    一篇文章让你搞懂原型和原型链
    数据库命令
    python序列(十)字典
    华为路由器基础知识和命令
    python列表(九)元组
    python初学者-计算小于100的最大素数
    python初学者-计算1-99奇数的和
    python初学者-使用for循环用四位数组成不同的数
    python初学者-使用for循环做一个九九乘法表
    python初学者-使用if条件语句判断成绩等级
  • 原文地址:https://www.cnblogs.com/xunzhen/p/10952031.html
Copyright © 2020-2023  润新知