4025: 二分图

4025: 二分图

链接

分析:

  线段树分治+并查集。

  以时间为下标建立一颗线段树,对于每条边u,v,l,r,在期出现的时间[l,r]的时间上打标记,表示时间[l,r]存在这条边,那么在线段树上递归到叶子结点,就是每个时刻所有出现的边。

  从根节点出发,把所有的边加入,并查集维护是否合法,如果到叶子结点了,依然是合法的,那么这个时刻就是可行的。

  退出一个点的时候,并查集中也要撤销的,所以不能路径压缩,可以按秩合并。

  如何判断是否合法?不存在奇环。即可以黑白染色。考虑并查集如果每个点的颜色。合并时,在并查集的根上打一个标记,如果存在这个标记,说明这个集合内的点的颜色取反。那么一个点的颜色就是从这个点出发,到根节点的路径上的异或和。

  同样可以CDQ分治,把每条线段拆成两个操作,在l出加入,在r处删除,询问T次。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define pa pair<int,int>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005;
int col[N], h[N], ans[N], fa[N];
vector< pa > e[N << 2];
struct OPT{ int x, y, f; };
vector<OPT> g[N << 2];

void update(int l,int r,int rt,int L,int R,int u,int v) {
    if (L > r || R < l) return ;
    if (L <= l && r <= R) {
        e[rt].push_back(pa(u, v)); return ;
    }
    int mid = (l + r) >> 1;
    if (L <= mid) update(l, mid, rt << 1, L, R, u, v);
    if (R > mid) update(mid + 1, r, rt << 1 | 1, L, R, u, v);
}
int findcol(int &x) {
    int c = 0;
    while (x != fa[x]) c ^= col[x], x = fa[x];
    return c;
}
void query(int l,int r,int rt) {
    bool flag = false;
    for (int i = 0; i < (int)e[rt].size(); ++i) {
        int x = e[rt][i].first, y = e[rt][i].second;
        int a = findcol(x), b = findcol(y);
        if (x == y) {
            if (a == b) {
                flag = true;
                for (int j = l; j <= r;  ++j) ans[j] = false;
                break;
            }
            continue;
        }
        if (h[x] < h[y]) swap(x, y);
        fa[y] = x, col[y] = a ^ b ^ 1;
        if (h[x] == h[y]) h[x] += 1;
        g[rt].push_back((OPT){x, y, (h[x] == h[y])});
    }
    int mid = (l + r) >> 1;
    if (!flag && l != r) query(l, mid, rt << 1), query(mid + 1, r, rt << 1 | 1);
    for (int i = g[rt].size() - 1; ~i; --i) {
        int x = g[rt][i].x, y = g[rt][i].y;
        fa[y] = y, col[y] = 0, h[x] -= g[rt][i].f;
    }
}
int main() {
    int n = read(), m = read(), T = read();
    for (int i = 1; i <= n; ++i) fa[i] = i, h[i] = 1;
    for (int i = 1; i <= T; ++i) ans[i] = 1;
    for (int i = 1; i <= m; ++i) {
        int u = read(), v = read(), l = read() + 1, r = read();
        if (l > r) continue; 
        update(1, T, 1, l, r, u, v);
    }
    query(1, T, 1);
    for (int i = 1; i <= T; ++i) puts(ans[i] ? "Yes" : "No");
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10501940.html