BZOJ 4025: 二分图

岁酱吖の 提交于 2019-11-26 23:32:26

4025: 二分图
思路:
考虑按时间分治,然后把每条边按影响时间加入相应的区间(类似划分树)。然后考虑把包含每个叶子节点的边连起来,并判断有没有奇环。
由于分治时需要撤回某些并查集的合并操作,所以需要用到可撤销并查集。然后因为要判基环,所以又需要维护每个点到父亲节点的距离\(dp[i]\)
所以需要用到带权并查集。
代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head
 
const int N = 1e5 + 5;
int n, m, T, u, v, l, r;
vector<pii> vc[N<<2];
bool ans[N];
struct UFS {
    stack<pair<int*, int> > stk;
    int fa[N], rnk[N], dp[N], c;
    inline void init(int n) {
        for (int i = 0; i <= n; ++i) fa[i] = i, rnk[i] = 0, dp[i] = 0;
        c = 0;
    }
    inline int Find(int x) {
        while(x^fa[x]) x = fa[x];
        return x;
    }
    inline int Deep(int x) {
        int res = 0;
        while(x^fa[x]) res += dp[x], x = fa[x];
        return res;
    }
    inline void Merge(int x, int y) {
        int fx = Find(x), fy = Find(y);
        if(fx == fy) {
            int dx = Deep(x), dy = Deep(y);
            if((dx+dy+1)%2) {
                stk.push(mp(&c, c));
                c++;
            }
            return ;
        }
        if(rnk[fx] <= rnk[fy]) {
            stk.push(mp(fa+fx, fa[fx]));
            stk.push(mp(dp+fx, dp[fx]));
            dp[fx] = dp[y]-dp[x]+1;
            fa[fx] = fy;
            if(rnk[fx] == rnk[fy]) {
                stk.push(mp(rnk+fy, rnk[fy]));
                rnk[fy]++;
            }
        }
        else {
            stk.push(mp(fa+fy, fa[fy]));
            stk.push(mp(dp+fy, dp[fy]));
            dp[fy] = dp[x]-dp[y]+1;
            fa[fy] = fx;
        }
    }
    inline void Undo() {
        *stk.top().fi = stk.top().se;
        stk.pop();
    }
}ufs;
void update(int L, int R, pii p, int rt, int l, int r) {
    if(L <= l && r <= R) return vc[rt].pb(p), void();
    int m = (l+r) >> 1;
    if(L <= m)update(L, R, p, ls);
    if(R > m) update(L, R, p, rs);
}
void dfs(int rt, int l, int r) {
    for (int i = 0; i < vc[rt].size();++i) ufs.Merge(vc[rt][i].fi, vc[rt][i].se);
    if(l == r) {
        if(ufs.c) printf("No\n");
        else printf("Yes\n");
        return ;
    }
    int sz = ufs.stk.size();
    int m = (l+r) >> 1;
    dfs(ls);
    while(ufs.stk.size() > sz) ufs.Undo();
    dfs(rs);
    while(ufs.stk.size() > sz) ufs.Undo();
}
int main() {
    scanf("%d %d %d", &n, &m, &T);
    for (int i = 1; i <= m; ++i) scanf("%d %d %d %d", &u, &v, &l, &r), update(l+1, r, {u, v}, 1, 1, T);
    ufs.init(n);
    dfs(1, 1, T);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!