zoukankan      html  css  js  c++  java
  • uoj207 共价大爷游长沙 子树信息 LCT + 随机化 + 路径覆盖

    题目传送门

    http://uoj.ac/problem/207

    题解

    如果是一棵静态的树,有一个非常容易想到的算法:统计一下目前的每一个条边被几条路径经过,如果 (x)(y) 的边的这个值为 (|S|) 的话,那么就是合法的。

    但是如果树是动态的,这个算法就有问题了。

    link 和 cut 会导致一个点对之间的路径发生改变。


    考虑到如果 (x)(y) 这条边必须要被经过的话,那么就是说覆盖了 (x)(y) 这条边的路径集恰好是 (S)

    回顾 bzoj3569 DZY Loves Chinese II 的做法,把一条路径用同一个 (int) 范围内随机的值在路径上的边都异或一边,那么如果两条边的值相同就意味着两条边很有可能是被相同的路径集覆盖。

    所以这题也同理,但是因为没有根,所以不能像一般的树一样做树上差分——所以我们直接求子树异或和就可以了。

    所以可用维护子树信息的 LCT 维护。


    时间复杂度 (O(mlog n))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 100000 + 7;
    const int M = 300000 + 7;
    
    #define lc c[0]
    #define rc c[1]
    
    int n, m, cnt, yz;
    int b[M];
    pii a[M];
    
    struct Node { int c[2], rev, fa, v, xsum, xs; } t[N];
    int st[N];
    inline bool idtfy(int o) { return t[t[o].fa].rc == o; }
    inline bool isroot(int o) { return t[t[o].fa].lc != o && t[t[o].fa].rc != o; }
    inline void connect(int fa, int o, int d) { t[fa].c[d] = o, t[o].fa = fa; }
    inline void pushup(int o) { t[o].xsum = t[t[o].lc].xsum ^ t[t[o].rc].xsum ^ t[o].xs ^ t[o].v; }
    inline void pushdown(int o) {
    	if (!t[o].rev) return;
    	if (t[o].lc) t[t[o].lc].rev ^= 1, std::swap(t[t[o].lc].lc, t[t[o].lc].rc);
    	if (t[o].rc) t[t[o].rc].rev ^= 1, std::swap(t[t[o].rc].lc, t[t[o].rc].rc);
    	t[o].rev = 0;
    }
    inline void rotate(int o) {
    	int fa = t[o].fa, pa = t[fa].fa, d1 = idtfy(o), d2 = idtfy(fa), b = t[o].c[d1 ^ 1];
    	if (!isroot(fa)) t[pa].c[d2] = o; t[o].fa = pa;
    	connect(o, fa, d1 ^ 1), connect(fa, b, d1);
    	pushup(fa), pushup(o);
    }
    inline void splay(int o) {
    	int x = o, tp = 0;
    	st[++tp] = x;
    	while (!isroot(x)) st[++tp] = x = t[x].fa;
    	while (tp) pushdown(st[tp--]);
    	while (!isroot(o)) {
    		int fa = t[o].fa;
    		if (isroot(fa)) rotate(o);
    		else if (idtfy(o) == idtfy(fa)) rotate(fa), rotate(o);
    		else rotate(o), rotate(o);
    	}
    }
    inline void access(int o) {
    	for (int x = 0; o; o = t[x = o].fa) {
    		splay(o);
    		t[o].xs ^= t[t[o].rc].xsum;
    		t[o].rc = x;
    		t[o].xs ^= t[t[o].rc].xsum;
    		pushup(o);
    	}
    }
    inline void mkrt(int o) {
    	access(o), splay(o);
    	t[o].rev ^= 1, std::swap(t[o].lc, t[o].rc);
    }
    inline int getrt(int o) {
    	access(o), splay(o);
    	while (pushdown(o), t[o].lc) o = t[o].lc;
    	return splay(o), o;
    }
    inline void link(int x, int y) {
    	mkrt(x);
    	if (getrt(y) != x) access(y), splay(y), t[x].fa = y, t[y].xs ^= t[x].xsum, pushup(y);
    }
    inline void cut(int x, int y) {
    	mkrt(x), access(y), splay(y);
    	if (t[y].lc == x && !t[x].rc) t[y].lc = t[x].fa = 0, pushup(y);
    }
    
    inline void work() {
    	while (m--) {
    		int opt, x, y, u, v;
    		read(opt);
    		if (opt == 1) {
    			read(x), read(y), read(u), read(v);
    			cut(x, y), link(u, v);
    		} else if (opt == 2) {
    			read(x), read(y);
    			v = rand(), yz ^= v;
    			access(x), splay(x), t[x].v ^= v, pushup(x);
    			access(y), splay(y), t[y].v ^= v, pushup(y);
    			a[++cnt] = pii(x, y), b[cnt] = v;
    		} else if (opt == 3) {
    			read(u);
    			x = a[u].fi, y = a[u].se, v = b[u], yz ^= v;
    			access(x), splay(x), t[x].v ^= v, pushup(x);
    			access(y), splay(y), t[y].v ^= v, pushup(y);
    		} else if (opt == 4) {
    			read(x), read(y);
    			mkrt(x), access(y), splay(x);
    			assert(t[x].rc == y && !t[y].lc);
    //			dbg("t[y].xsum = %d, yz = %d, %d, %d
    ", t[y].xsum, yz, t[y].v, t[y].xs);
    			if (t[y].xsum != yz) puts("NO");
    			else puts("YES");
    		}
    	}
    }
    
    inline void init() {
    	srand(time(0) + (ull)new char);
    	read(n), read(n), read(m);
    	int x, y;
    	for (int i = 1; i < n; ++i) read(x), read(y), link(x, y);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    HTML5新特性之文件和二进制数据的操作
    HTML5本地存储之IndexedDB
    HTML5新标签之Canvas
    HTML5 Canvas实战之烟花效果
    Asp.NET core/net 5接口返回实体含有long/int64的属性序列后最后几位变为0的解决
    Aero for WTL application
    C++WTL基于MCI的音频播放器源码
    c++ 深拷贝,浅拷贝,赋值操作的调用情况
    发布一个生成按钮图片的工具 c#写的
    贴图:CImage VS Bitmap
  • 原文地址:https://www.cnblogs.com/hankeke/p/uoj207.html
Copyright © 2011-2022 走看看