1 条题解

  • 0
    @ 2023-3-14 14:31:13

    题意可以转化为支持删边,询问两个点是否在同一个边双连通分量里。

    删边不好操作,考虑离线转为加边。

    发现边双联通就相当于是一个环,因此我们考虑用 lctlct 维护一棵树,然后对于一次加边操作,如果不联通就是直接 linklink,否则说明这条路径上的点都在同一个边双里,可以直接将路径上的边赋值为 11,然后 checkcheck 的时候先判是否联通,如果联通就判路径上是否都为 11,正确性不难证明。

    同时反向加边的时候记得开 multisetmultiset,但是这题好像数据水不开也能过。

    # include <cstdio>
    # include <set>
    # include <vector>
    # include <utility>
    # include <algorithm>
    
    using std::swap;
    using std::minmax;
    
    typedef std::pair<int, int> pii;
    
    const int MAXN = 1e5 + 5;
    
    int n, m, q, totN;
    
    std::multiset<pii> mp;
    
    struct Edge {
    	int x, y;
    } e[MAXN << 1];
    
    struct QQ {
    	int op, x, y;
    	
    	QQ() {}
    	QQ(int O, int X, int Y) {
    		op = O, x = X, y = Y;
    	}
    }; std::vector<QQ> Q;
    
    namespace LCT {
    	struct Splay {
    		int son[2], fa; int siz, sum, val; bool rev, tag;
    	} tr[MAXN << 1];
    	
    	bool Get(int u) {
    		return tr[ tr[u].fa ].son[1] == u;
    	}
    	
    	void pushup(int u) {
    		int ls = tr[u].son[0], rs = tr[u].son[1];
    		tr[u].siz = tr[ls].siz + tr[rs].siz + 1;
    		tr[u].sum = tr[ls].sum + tr[rs].sum + tr[u].val;
    	}
    	
    	bool isRt(int u) {
    		return tr[ tr[u].fa ].son[0] != u && tr[ tr[u].fa ].son[1] != u;
    	}
    	
    	void updRev(int u, bool flg) {
    		if (!flg) return;
    		swap(tr[u].son[0], tr[u].son[1]), tr[u].rev ^= 1;
    	}
    	
    	void updCov(int u, bool flg) {
    		if (!flg) return;
    		tr[u].val = 1, tr[u].sum = tr[u].siz, tr[u].tag = true;
    	}
    	
    	void pushdown(int u) {
    		int ls = tr[u].son[0], rs = tr[u].son[1];
    		if (ls) updCov(ls, tr[u].tag), updRev(ls, tr[u].rev);
    		if (rs) updCov(rs, tr[u].tag), updRev(rs, tr[u].rev);
    		tr[u].rev = tr[u].tag = false;
    	}
    	
    	void pushall(int u) {
    		if (!isRt(u)) pushall(tr[u].fa); pushdown(u);
    	}
    	
    	void rotate(int u) {
    		int fa = tr[u].fa, Gf = tr[fa].fa;
    		bool x = Get(u), y = Get(fa);
    		if (!isRt(fa)) tr[Gf].son[y] = u; tr[u].fa = Gf;
    		tr[fa].son[x] = tr[u].son[x ^ 1], tr[ tr[fa].son[x] ].fa = fa;
    		tr[u].son[x ^ 1] = fa, tr[fa].fa = u;
    		pushup(fa), pushup(u);
    	}
    	
    	void splay(int u) {
    		pushall(u);
    		while (!isRt(u)) {
    			int fa = tr[u].fa;
    			if (!isRt(fa)) rotate(Get(u) ^ Get(fa) ? u : fa);
    			rotate(u);
    		}
    	}
    	
    	void access(int u) {
    		int tmp = u;
    		for (int v = 0; u; v = u, u = tr[u].fa)
    			splay(u), tr[u].son[1] = v, pushup(u);
    		splay(tmp);
    	}
    	
    	void mkRt(int u) {
    		access(u), updRev(u, true);
    	}
    	
    	int findRt(int u) {
    		access(u);
    		while (tr[u].son[0])
    			pushdown(u), u = tr[u].son[0];
    		return splay(u), u;
    	}
    	
    	void link(int u, int v) {
    		mkRt(u), tr[u].fa = v;
    	}
    	
    	void split(int u, int v) {
    		mkRt(u), access(v);
    	}
    	
    	void modify(int u, int v) {
    		if (findRt(u) != findRt(v)) 
    			return link(u, ++n), link(n, v);
    		split(u, v), updCov(v, true);
    	}
    	
    	bool query(int u, int v) {
        if (findRt(u) != findRt(v)) return false;
    		split(u, v);
    		return tr[v].siz == tr[v].sum;
    	}
    }
    using LCT::modify;
    using LCT::query;
    
    int main() {
    	
    	// freopen("2.in", "r", stdin);
    	// freopen("std.out", "w", stdout);
    	
    	scanf("%d %d %d", &n, &m, &q);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d %d", &e[i].x, &e[i].y), mp.emplace(minmax(e[i].x, e[i].y));
    	}
    	for (int i = 1; i <= q; ++i) {
    		char op[10]; int x, y;
    		scanf("%s %d %d", op, &x, &y);
    		switch (op[0]) {
    			case 'Z' : Q.emplace_back(1, x, y); if (mp.find(minmax(x, y)) != mp.end()) mp.erase(mp.find(minmax(x, y))); break;
    			case 'P' : Q.emplace_back(2, x, y); break;
    			default : puts(">_<");
    		}
    	}
    	for (auto [x, y] : mp) modify(x, y);
    	std::reverse(Q.begin(), Q.end());
    	std::vector<bool> vec;
    	for (QQ x : Q) {
    		switch (x.op) {
    			case 1 : modify(x.x, x.y); break;
    			case 2 : vec.push_back(query(x.x, x.y)); break;
    			default : puts(">_<");
    		}
    	}
    	std::reverse(vec.begin(), vec.end());
    	for (bool x : vec) puts(x ? "Yes" : "No");
    
    	return 0;
    }
    
    • 1

    信息

    ID
    4229
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    21
    已通过
    1
    上传者