• BZOJ4025: 二分图【线段树分治】【带撤销的并查集】


    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。


    感觉是套路

    不过没关系,就是连连线段树分治


    有一些需要注意的细节

    • dfs的时候就算到达了叶节点别忘了删除加入的边

    • 并查集合并需要启发式的,并且需要用异或值来维护路径奇偶性

      然后如果当前加入边,一定要保证((u,v))距离是奇数,所以用异或计算一下合并根节点的距离

    • 注意清空dep这个数组


    剩下的就很套路的分解线段,很套路的dfs,很套路的并查集维护就可以了


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 2e5 + 10;
    #define mp make_pair
    #define fi first
    #define se second
    typedef pair<int, int> pi;
    typedef pair<pi, pi> pii;
    
    #define LD (t << 1) 
    #define RD (t << 1 | 1)
    vector<pi> g[N << 2];
    
    void modify(int t, int l, int r, int ql, int qr, pi edge) {
      if (ql <= l && r <= qr) {
        g[t].push_back(edge);
        return;
      }
      int mid = (l + r) >> 1;
      if (qr <= mid) modify(LD, l, mid, ql, qr, edge);
      else if (ql > mid) modify(RD, mid + 1, r, ql, qr, edge);
      else {
        modify(LD, l, mid, ql, mid, edge);
        modify(RD, mid + 1, r, mid + 1, qr, edge);
      }
    }
    
    stack<pair<pii, pi> > st;
    int dep[N], height[N], fa[N];
    int ans = 1;
    
    int Find(int x) {
      if (x == fa[x]) return x;
      return Find(fa[x]);
    }
    
    int Getdep(int x) {
      if (x == fa[x]) return 0;
      return dep[x] ^ Getdep(fa[x]);
    }
    
    void Merge(int u, int v) {
      int fau = Find(u), fav = Find(v);
      st.push(mp(mp(mp(fau, fav), mp(height[fau], height[fav])), mp(ans, fau != fav)));  
      int w = Getdep(u) ^ Getdep(v);
      if (fau == fav) {
        if (!(w & 1)) ans = 0;
        return;
      }
      if (height[fau] == height[fav]) {
        fa[fav] = fau;
        dep[fav] = w ^ 1;
        ++height[fau];
      } else if (height[fau] > height[fav]) {
        fa[fav] = fau;
        dep[fav] = w ^ 1;
      } else {
        fa[fau] = fav;
        dep[fau] = w ^ 1;
      }
    }
    
    void Delete() {
      pair<pii, pi> now = st.top(); st.pop();
      ans = now.se.fi;
      if (!now.se.se) return;
      int u = now.fi.fi.fi, heightu = now.fi.se.fi;
      int v = now.fi.fi.se, heightv = now.fi.se.se;
      if (heightu == heightv) {
        fa[v] = v;
        dep[v] = 0;
        --height[u];
      } else if (heightu > heightv) {
        fa[v] = v;
        dep[v] = 0;
      } else {
        fa[u] = u;
        dep[u] = 0;
      }
    }
    
    void dfs(int t, int l, int r) {
      fv(i, g[t]) Merge(g[t][i].fi, g[t][i].se);
      if (!ans) {
        fu(i, l, r) printf("No
    ");
      } else {
        if (l == r) {
          printf("Yes
    ");
        } else {
          int mid = (l + r) >> 1;
          dfs(LD, l, mid);
          dfs(RD, mid + 1, r);
        }
      }
      fv(i, g[t]) Delete();
    }
    
    int n, m, T;
    int main() {
      freopen("input.txt", "r", stdin);
      Read(n), Read(m), Read(T);
      fu(i, 1, n) fa[i] = i, height[i] = 1, dep[i] = 1;
      fu(i, 1, m) {
        int u, v, s, t;
        Read(u), Read(v), Read(s), Read(t);
        if (++s > t) continue;
        modify(1, 1, T, s, t, mp(u, v));
      }
      dfs(1, 1, T);
      return 0;
    }
    
  • 相关阅读:
    数据结构与算法分析
    案例分析作业
    实验六——循环结构程序练习总结
    实验五——循环结构学习总结
    实验四——多分支结构及本章总结
    实验三——for 语句及分支结构else-if
    第二次作业及总结——数据类型和运算符
    2-c语言作业
    自然博物馆参观
    2019-2020-1学期 20192409《网络空间安全专业导论》第四周学习总结
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9864003.html
Copyright © 2020-2023  润新知