1. 程式人生 > >【離線 線段樹分治】bzoj4025: 二分圖

【離線 線段樹分治】bzoj4025: 二分圖

昨天mac的gdb掛了,今天怎麼筆記本的gdb也掛了……

Description

神犇有一個n個節點的圖。因為神犇是神犇,所以在T時間內一些邊會出現後消失。神犇要求出每一時間段內這個圖是否是二分圖。這麼簡單的問題神犇當然會做了,於是他想考考你。

Input

輸入資料的第一行是三個整數n,m,T。 第2行到第m+1行,每行4個整數u,v,start,end。第i+1行的四個整數表示第i條邊連線u,v兩個點,這條邊在start時刻出現,在第end時刻消失。

Output

輸出包含T行。在第i行中,如果第i時間段內這個圖是二分圖,那麼輸出“Yes”,否則輸出“No”,不含引號。

Sample Input

3 3 3
1 2 0 2
2 3 0 3
1 3 1 2

Sample Output

Yes
No
Yes

HINT

樣例說明: 0時刻,出現兩條邊1-2和2-3。 第1時間段內,這個圖是二分圖,輸出Yes。 1時刻,出現一條邊1-3。 第2時間段內,這個圖不是二分圖,輸出No。 2時刻,1-2和1-3兩條邊消失。 第3時間段內,只有一條邊2-3,這個圖是二分圖,輸出Yes。
資料範圍: n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。

題目分析

線段樹分治一樣的套路

重點在於如何判斷一張圖是否是二分圖。我們知道二分圖的充要條件是無奇環的森林:那麼奇環的成立條件是在並查集合並時,所連邊的兩個點在原樹中的路徑長度為偶數。用$d[x]$表示$x$點在並查集結構中,到其父親的路徑奇偶性;初始每個點獨自為根,則$d[x]=0$。每當兩個不同的集合合併時,就應該 d[fx]=get(x)^get(y)^1 ,相當於是在並查集中維護了原圖的結構。

可以用以上這幅圖理解。

第一遍寫的時候,想當然地混淆了按秩合併並查集和原圖這兩個樹形結構,get的時候直接^1地跳了。

 

 1 #include<bits/stdc++.h>
 2
const int maxn = 100035; 3 const int maxm = 200035; 4 const int maxt = 100035; 5 const int maxOpt = 200035; 6 7 int n,m,T; 8 struct Edge 9 { 10 int u,v,s,t; 11 Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),s(c),t(d) {} 12 }tmp; 13 typedef std::vector<Edge> vec; 14 struct Dsu 15 { 16 int top,fat[maxn],size[maxn],d[maxn]; 17 std::pair<int, int> stk[maxOpt]; 18 void init(){for (int i=1; i<=n; i++) fat[i] = i, size[i] = 1;} 19 int find(int x){while (x!=fat[x]) x = fat[x];return x;} 20 int get(int x){int ret = 0;while(x!=fat[x]) ret ^= d[x], x = fat[x];return ret;} 21 bool merge(int x, int y) 22 { 23 int fx = find(x), fy = find(y); 24 if (fx==fy) return get(x)^get(y)^1; 25 if (size[fx] > size[fy]) std::swap(fx, fy); 26 fat[fx] = fy, size[fy] += size[fx]; 27 d[fx] = get(x)^get(y)^1; 28 stk[++top] = std::make_pair(fx, fy); 29 return 0; 30 } 31 void cancel() 32 { 33 int x = stk[top].first, y = stk[top].second; 34 fat[x] = x, size[y] -= size[x], --top, d[x] = 0; 35 } 36 }dsu; 37 bool ans[maxt]; 38 vec opt; 39 40 int read() 41 { 42 char ch = getchar(); 43 int num = 0, fl = 1; 44 for (; !isdigit(ch); ch=getchar()) 45 if (ch=='-') fl = -1; 46 for (; isdigit(ch); ch=getchar()) 47 num = (num<<1)+(num<<3)+ch-48; 48 return num*fl; 49 }
51 void solve(int l, int r, vec opt) 52 { 53 vec L,R; 54 int mid = (l+r)>>1, tmp = dsu.top; 55 for (int i=0, mx=opt.size(); i<mx; i++) 56 { 57 int s = opt[i].s, t = opt[i].t; 58 if (s <= l&&r <= t){ 59 if (dsu.merge(opt[i].u, opt[i].v)){ 60 while (tmp!=dsu.top) dsu.cancel(); 61 return; 62 } 63 }else{ 64 if (s <= mid) L.push_back(opt[i]); 65 if (t > mid) R.push_back(opt[i]); 66 } 67 } 68 if (l==r) ans[l] = 1; 69 else solve(l, mid, L), solve(mid+1, r, R); 70 while (tmp!=dsu.top) dsu.cancel(); 71 } 72 int main() 73 { 74 n = read(), m = read(), T = read(), dsu.init(); 75 for (int i=1; i<=m; i++) 76 { 77 tmp.u = read(), tmp.v = read(), tmp.s = read()+1, tmp.t = read(); 78 if (tmp.s <= tmp.t) opt.push_back(tmp); 79 } 80 solve(1, T, opt); 81 for (int i=1; i<=T; i++) puts(ans[i]?"Yes":"No"); 82 return 0; 83 }

 

 

END