BZOJ 4229选择

1|0BZOJ 4229选择

Link

1|1题目分析:

看到删除,直接进行考虑倒过来进行加点,那么这样的话就就进行加边,然后查询两个点是否在同一个点边双中。虽然但是,这个东西真的可以用 LCT 进行维护,只需要加上一个并查集即可。那么并查集维护两个点是否属于同一个边双,如果是的话,那么利用一个并查集压缩这一条链。

总之就是分为两种情况。

  1. 如果原来不相连的话,那么直接连上就行了
  2. 如果在一颗 LCT 里面的话,那么直接把一个点提到根上然后直接缩这一条链即可。

1|2Code:

//editor : DRYAYST //Wo shi ge da SHA BI #include<bits/stdc++.h> #define g() getchar() #define il inline #define ull unsigned long long #define eps 1e-10 #define ll long long #define pa pair<int, int> #define for_1(i, n) for(int i = 1; i <= (n); ++i) #define for_0(i, n) for(int i = 0; i < (n); ++i) #define for_xy(i, x, y) for(int i = (x); i <= (y); ++i) #define for_yx(i, y, x) for(int i = (y); i >= (x); --i) #define for_edge(i, x) for(int i = head[x]; i; i = nxt[i]) #define int long long #define DB double #define m_p make_pair #define fi first #define se second using namespace std; const int N = 1e6 + 10, INF = 0x7f7f7f7f, mod = 1e9 + 7; il int qpow(int x, int k) {int ans = 1; while(k) {if(k & 1) ans = ans * x % mod; x = x * x % mod; k >>= 1; } return ans; } il int Add(int x, int y) {return (x += y) %= mod;} il int Del(int x, int y) {return (x = x - y + mod) % mod;} il int Mul(int x, int y) {return x * y % mod;} il int inv(int x) {return qpow(x, mod - 2); } inline int re() { int x = 0, p = 1; char ch = getchar(); while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();} while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * p; } int n, m, q; int ans[N], fa1[N], fa2[N]; int get1(int x) {return x == fa1[x] ? x : fa1[x] = get1(fa1[x]); } int get2(int x) {return x == fa2[x] ? x : fa2[x] = get2(fa2[x]); } set<pa> s; struct Node {int x, y, op; }Q[N], e[N]; #define ls c[x][0] #define rs c[x][1] int fa[N], c[N][2], st[N]; bool r[N]; il bool nroot(int x) {return c[get2(fa[x])][0] == x || c[get2(fa[x])][1] == x; } il bool tp(int x) {return c[get2(fa[x])][1] == x; } il void pushdown(int x) {if(r[x]){swap(c[ls][0], c[ls][1]); swap(c[rs][0], c[rs][1]); r[ls] ^= 1; r[rs] ^= 1; r[x] = 0; }} il void rotate(int x) { int y = get2(fa[x]), z = get2(fa[y]), k = tp(x); if(nroot(y)) c[z][tp(y)] = x; c[y][k] = c[x][!k]; c[x][!k] = y; fa[c[y][k]] = y; fa[y] = x; fa[x] = z; } il void splay(int x) { int y = x, z = 0; st[++z] = y; while(nroot(y)) y = get2(fa[y]), st[++z] = y ; while(z) pushdown(st[z]), z--; while(nroot(x)) { int y = get2(fa[x]); if(nroot(y)) {rotate(tp(x) == tp(y) ? y : x); } rotate(x); } } il void access(int x) {int y = 0; for(; x; y = x, x = get2(fa[x])) splay(x), rs = y; } il void makeroot(int x) {access(x); splay(x); swap(ls, rs), r[x] ^= 1; } void BL(int x) { if(fa[x]) fa2[x] = get2(fa[x]); if(ls) BL(ls); if(rs) BL(rs); } il void link(int x, int y) { x = get2(x), y = get2(y); if(x == y) return; if(get1(x) != get1(y)) {makeroot(x); fa[x] = y; fa1[get1(x)] = get1(y);} else {makeroot(x); access(y); splay(y); BL(y);} } #undef ls #undef rs signed main() { freopen("choice.in","r",stdin); freopen("choice.out","w",stdout); n = re(), m = re(), q = re(); for_1(i, m) {int x = re(), y = re(); if(x > y) swap(x, y); e[i].x = x, e[i].y = y;} for_1(i, q) {char op; scanf("%s", &op); int x = re(), y = re(); if(x > y) swap(x, y); Q[i].x = x; Q[i].y = y; Q[i].op = (op == 'Z') ? 1 : 2; if(op == 'Z') s.insert(m_p(x, y));} for_1(i, n) fa1[i] = fa2[i] = i; for_1(i, m) if(!s.count(m_p(e[i].x, e[i].y))) {link(e[i].x, e[i].y); } for(int i = q; i; --i) {if(Q[i].op == 1) link(Q[i].x , Q[i].y); else ans[i] = (get2(Q[i].x) == get2(Q[i].y)); } for_1(i, q) {if(Q[i].op == 2) printf(ans[i] ? "Yes\n" : "No\n");} } /* 7 8 7 1 2 1 3 1 4 2 3 3 4 3 7 7 4 5 6 Z 1 4 P 1 3 P 2 4 Z 1 3 P 1 3 Z 6 5 P 5 6 */

__EOF__

本文作者Zwaire
本文链接https://www.cnblogs.com/Zwaire/p/16137686.html
关于博主:这个世界除了你,都知道我喜欢你
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Zwaire  阅读(39)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示