[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;
}
posted @ 2017-10-04 10:16  HLX_Y  阅读(187)  评论(0编辑  收藏  举报