[LOJ#121]動態圖連通性
試題描述
這是一道模板題。
你要維護一張無向簡單圖。你被要求加入刪除一條邊及查詢兩個點是否連通。
- 0:加入一條邊。保證它不存在。
- 1:刪除一條邊。保證它存在。
- 2:查詢兩個點是否聯通。
輸入
輸入的第一行是兩個數 N M。N=5000,M≤500000。
接下來 M 行,每一行三個數 op x y。 op 表示操作編號。
輸出
對於每一個
op=2 的詢問,輸出一行
Y
或 N
,表示兩個節點是否連通。
輸入示例1
200 5 2 123 127 0 123 127 2 123 127 1 127 123 2 123 127
輸出示例1
N
Y
N
輸入示例2
4 10 0 1 2 0 2 3 0 3 1 2 1 4 0 4 3 2 1 4 1 2 3 2 1 4 1 1 3 2 1 4
輸出示例2
N
Y
Y
N
數據規模及約定
對於數據點 1,N≤200,M≤200
對於數據點 2,N=5,M≤30
對於數據點 3,N=10,M≤1000,其中查詢的次數 >=900 次。
對於數據點 4,N=300,M≤50000
對於數據點 5,N=5000,M≤200000,沒有操作 1,其中約70是操作2。
對於數據點 6,N=5000,M≤200000,沒有操作 1,其中約70是操作0。
對於數據點 7、8,N=100,M≤500000
對於數據點 9,N=5000,M≤500000,圖是一棵樹,其直徑 ≤6 。
對於數據點 10, N=5000,M≤500000,圖是一棵樹,其每個點度數 ≤4 。
P.S. 其實 9 是菊花,10 是單鏈,而沒有放隨機樹的點...
題解
動態樹模板練習。(離線,維護刪除時間最大生成樹)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 505010 #define oo 2147483647 struct Node { int siz, tim, mni; bool rev; Node(): rev(0) {} Node(int _): tim(_) {} }; struct LCT { Node ns[maxn]; int ch[maxn][2], fa[maxn]; int S[maxn], top; int _siz, _mni; bool isrt(int u) { return !fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u); } void pushdown(int o) { if(!ns[o].rev) return ; swap(ch[o][0], ch[o][1]); for(int i = 0; i < 2; i++) if(ch[o][i]) ns[ch[o][i]].rev ^= 1; ns[o].rev = 0; return ; } void maintain(int o) { ns[o].siz = 1; ns[o].mni = o; for(int i = 0; i < 2; i++) if(ch[o][i]) { ns[o].siz += ns[ch[o][i]].siz; int& tmp = ns[o].mni; if(ns[tmp].tim > ns[ns[ch[o][i]].mni].tim) tmp = ns[ch[o][i]].mni; } return ; } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(!isrt(y)) ch[z][ch[z][1]==y] = u; if(ch[y][1] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[u][r]] = y; ch[y][l] = ch[u][r]; ch[u][r] = y; maintain(y); return ; } void splay(int u) { int t = u; S[top = 1] = t; while(!isrt(t)) S[++top] = fa[t], t = fa[t]; while(top) pushdown(S[top--]); while(!isrt(u)) { int y = fa[u], z = fa[y]; if(!isrt(y)) { if(ch[y][0] == u ^ ch[z][0] == y) rotate(u); else rotate(y); } rotate(u); } return maintain(u); } void access(int u) { splay(u); ch[u][1] = 0; maintain(u); while(fa[u]) splay(fa[u]), ch[fa[u]][1] = u, maintain(fa[u]), splay(u); return ; } void makert(int u) { access(u); ns[u].rev ^= 1; return ; } void link(int a, int b) { // printf("link(%d, %d)\n", a, b); makert(b); fa[b] = a; return ; } void cut(int a, int b) { // printf("cut(%d, %d)\n", a, b); makert(a); access(b); ch[b][0] = fa[a] = 0; return maintain(b); } void query(int a, int b) { // printf("query(%d, %d)\n", a, b); makert(b); access(a); _siz = ns[a].siz; _mni = ns[a].mni; return ; } bool together(int a, int b) { // printf("together(%d, %d)\n", a, b); if(a == b) return 1; makert(b); access(a); bool ok = 0; while(ch[a][0]) { a = ch[a][0]; if(a == b){ ok = 1; break; } } splay(a); return ok; } } sol; #define pii pair <int, int> #define x first #define y second #define mp(x, y) make_pair(x, y) struct Que { int tp, a, b, e; Que() {} Que(int _1, int _2, int _3): tp(_1), a(_2), b(_3) {} } qs[maxn]; pii edges[maxn]; int uid[25010010]; int lstdel[maxn], cntn; int code(pii e) { return e.x * 5001 + e.y; } int main() { int n = cntn = read(), m = read(); for(int i = 1; i <= m; i++) { int tp = read(), a = read(), b = read(); if(a > b) swap(a, b); qs[i] = Que(tp, a, b); } for(int i = m; i; i--) { int tp = qs[i].tp, a = qs[i].a, b = qs[i].b; if(tp == 1) { pii e = mp(a, b); lstdel[qs[i].e = uid[code(e)] = ++cntn] = i; edges[cntn] = e; } if(tp == 0) { pii e = mp(a, b); if(uid[code(e)]) qs[i].e = uid[code(e)], uid[code(e)] = 0; else lstdel[qs[i].e = ++cntn] = m + 1, edges[cntn] = e; } } for(int i = 1; i <= n; i++) sol.ns[i] = Node(oo); for(int i = n + 1; i <= cntn; i++) sol.ns[i] = Node(lstdel[i]); for(int i = 1; i <= m; i++) { int tp = qs[i].tp, a = qs[i].a, b = qs[i].b, e = qs[i].e; if(tp == 0) { if(!sol.together(a, b)) sol.link(a, e), sol.link(e, b); else { sol.query(a, b); if(lstdel[sol._mni] < lstdel[e]) { sol.cut(edges[sol._mni].x, sol._mni); sol.cut(sol._mni, edges[sol._mni].y); sol.link(a, e); sol.link(e, b); } } } if(tp == 1) { sol.query(a, b); if(sol._siz == 3) sol.cut(a, e), sol.cut(b, e); } if(tp == 2) puts(sol.together(a, b) ? "Y" : "N"); } return 0; }