• [bzoj4025] 二分图


    题意:给出n个点,m条边,每条边有一个出现时间和一个消失时间,问从0-T的时间内,每个时间点的图是否是二分图

    题解:

    分治+并查集(按秩合并+带权)

    众所周知的结论:二分图一定不存在奇环,存在奇环的图一定不是二分图

    对时间分治,维护([l,r])时间内存在的边,对每条边讨论:

    1、当前边的起止时间刚好与([l,r])相等,那么判断这条边所在的连通块是否构成奇环(让结点带权,记一下到根要经过奇数条边还是偶数条边即可),若成奇环,则([l,r])时间内都为"No",否则这条边加入图中

    2、若终止时间小于等于mid,则划分到左区间

    3、若起始时间大于mid,则划分到右区间

    4、否则两个区间一起丢

    当l==r时,则输出"Yes"

    注意:回溯时并查集要恢复到进入前的状态

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define ll long long
    #define N 100010
    using namespace std;
    
    int n,m,T,top;
    int stk[N],fa[N],dis[N],rank[N];
    
    struct Node {int x,y,s,t;};
    
    vector<Node> ve;
    
    int gi() {
      int x=0,o=1; char ch=getchar();
      while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
      if(ch=='-') o=-1,ch=getchar();
      while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
      return o*x;
    }
    
    int find(int x) {
      return x==fa[x]?x:find(fa[x]);
    }
    
    int get_dis(int x) {
      int ret=0;
      while(x!=fa[x]) ret^=dis[x],x=fa[x];
      return ret;
    }
    
    void unite(int x, int y, int z) {
      int xx=find(x),yy=find(y);
      if(xx==yy) return;
      if(rank[yy]>rank[xx]) swap(xx,yy);
      if(rank[yy]==rank[xx]) rank[xx]++,stk[++top]=-xx;
      fa[yy]=xx,dis[yy]=z,stk[++top]=yy;
    }
    
    void restore(int now) {
      while(top>now) {
        if(stk[top]<0) rank[-stk[top]]--;
        else fa[stk[top]]=stk[top],dis[stk[top]]=0;
        top--;
      }
    }
    
    void bs(int l, int r, vector<Node> &e) {
      int mid=(l+r)>>1,now=top,sz=e.size();
      vector<Node> vl,vr;
      for(int i=0; i<sz; i++) {
        Node u=e[i];
        int x=u.x,y=u.y;
        if(l==u.s && r==u.t) {
          int xx=find(x);
          int yy=find(y);
          int zz=get_dis(x)^get_dis(y)^1;
          if(xx!=yy) unite(x,y,zz); 
          else if(zz&1) {
    	for(int j=l; j<=r; j++) puts("No");
    	restore(now);
    	return;
          }
        }
        else if(u.t<=mid) vl.push_back(u);
        else if(u.s>mid) vr.push_back(u);
        else vl.push_back((Node){x,y,u.s,mid}),vr.push_back((Node){x,y,mid+1,u.t});
      }
      if(l==r) puts("Yes");
      else bs(l,mid,vl),bs(mid+1,r,vr);
      restore(now);
    }
    
    int main() {
      n=gi(),m=gi(),T=gi();
      for(int i=1; i<=n; i++) fa[i]=i;
      for(int i=1; i<=m; i++) {
        int x=gi(),y=gi(),s=gi()+1,t=gi();
        if(s>t) continue;
        ve.push_back((Node){x,y,s,t});
      }
      bs(1,T,ve);
      return 0;
    }
    
  • 相关阅读:
    2017年软件工程基础-个人项目作业
    [2017BUAA软工]第1次个人作业
    [2017BUAA软工]第0次个人作业
    个人作业——软件工程实践总结&个人技术博客
    个人作业——软件评测
    结对第二次作业
    软件工程结对作业
    寒假作业(2/2)
    软件工程寒假快乐作业
    技术总结——Vue页面刷新的方法
  • 原文地址:https://www.cnblogs.com/HLXZZ/p/7625297.html
Copyright © 2020-2023  润新知