【Luogu P5787】二分圖 /【模板】線段樹分治
阿新 • • 發佈:2021-08-13
連結:
題目大意:
有一個 \(n\) 個節點的圖,在 \(k\) 時間內有 \(m\) 條邊會出現後消失,要求出每一時間段內這個圖是否是二分圖。
思路:
線段樹分治用於離線、可撤銷類的題目。
線段樹維護某時間內連的邊。統計答案時,用擴充套件域並查集查詢連邊是否合法。並查集不可路徑壓縮,因為要用棧回溯。
程式碼:
const int N = 3e5 + 10; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } int n, m, k; struct node { int l, r, st, ed; }e[N]; vector <int> t[N << 3]; void Modify(int p, int l, int r, int L, int R, int id) { if (l > R || r < L) return; if (L <= l && r <= R) { t[p].push_back(id); return; } int mid = l + r >> 1; Modify (p << 1, l, mid, L, R, id); Modify (p << 1 | 1, mid + 1, r, L, R, id); } struct Stack { int x, y, add; }; int top = 0; Stack stk[N << 2]; int fa[N << 1], height[N << 1]; int Find(int k) {return k == fa[k]? k: fa[k] = Find(fa[k]);} void Merge (int u, int v) { int x = Find(u), y = Find(v); if (height[x] > height[y]) x ^= y ^= x ^= y; stk[++top] = (Stack){x, y, height[x] == height[y]}; fa[x] = y; if(height[x] == height[y]) height[y]++; } void Solve (int p, int l, int r) { int flag = 1, lsttop = top; for (int i = 0; i < t[p].size(); i++) { int u = e[t[p][i]].l, v = e[t[p][i]].r; int x = Find(u), y = Find(v); if (x == y) { for (int j = l; j <= r; j++) printf ("No\n"); flag = 0; break; } Merge (u, v + n); Merge (v, u + n); } if (flag) { if (l == r) printf ("Yes\n"); else { int mid = l + r >> 1; Solve (p << 1, l, mid); Solve (p << 1 | 1, mid + 1, r); } } for (; top > lsttop; top--) height[fa[stk[top].x]] -= stk[top].add, fa[stk[top].x] = stk[top].x; } int main() { n = Read(), m = Read(), k = Read(); int cnt = 0; for (int i = 1; i <= m; i++) { e[i].l = Read(), e[i].r = Read(), e[i].st = Read(), e[i].ed = Read(); Modify(1, 1, k, e[i].st + 1, e[i].ed, i); } for (int i = 0; i <= n * 2; i++) fa[i] = i, height[i] = 1; Solve (1, 1, k); return 0; }