bzoj 4025: 二分图 (分治+图论)

我们注意到如果出现奇环就爆炸,所以我们维护并查集即可,但是如果要连u,v我们考虑u、v到根的距离分别为x,y如果(x+y)%2==0那么根直接合并,但是如果是奇数那么久新建一个点变成x和y的父亲,注意用深度维护平衡。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#define xx first
#define yy second
#define mp(a,b) make_pair(a,b)
using namespace std;
typedef long long LL;
typedef double db;
const int maxn=200005;
int ans[maxn];
struct pi{
	int u,v;
	int l,r;
}pp;
int fa[maxn];
int dep[maxn];
typedef pair<int ,int>p1;
int cnt;
void divide(int l,int r,vector<pi>g){
	int p=g.size();
	vector<p1>gg;
	gg.clear();
	int flag=0;
    int pre=cnt;
	for(int i=0;i<p;i++){
		if(g[i].l<=l&&g[i].r>=r){
			int x=g[i].u;
			int x1=0;
			int y=g[i].v;
			int y1=0;
			while(fa[x]!=x){
				x=fa[x];
				x1++;
			}
			while(fa[y]!=y){
				y=fa[y];
				y1++;
			}
			gg.push_back(mp(x,dep[x]));
			gg.push_back(mp(y,dep[y]));
			if(x==y){
				if((x1+y1)%2==0)
				flag=1;
			}
			else{
                if((x1+y1)%2==0){
                    if(dep[x]<dep[y]){
                        swap(x,y);
                    }
                    fa[y]=x;
                    dep[x]=max(dep[x],dep[y]+1);
                }
                else{
                    ++cnt;
                    fa[x]=cnt;
                    fa[y]=cnt;
                    fa[cnt]=cnt;
                    dep[cnt]=max(dep[x],dep[y]);
                }
			}
		}
	}
	if(flag){
		for(int i=l;i<=r;i++) ans[i]=1;
	}
	if(l==r){
		p=gg.size();
		for(int i=p-1;i>=0;i--){
			fa[gg[i].xx]=gg[i].xx;
			dep[gg[i].xx]=gg[i].yy;
		}
		gg.clear();
        cnt=pre;
		return ;
	}
	int mid=(l+r)/2;
	vector<pi>g1,g2;
	g1.clear();
	g2.clear();
	for(int i=0;i<p;i++){
		if(g[i].l<=l&&g[i].r>=r) continue;
		if(g[i].l<=mid) g1.push_back(g[i]);
		if(g[i].r>mid) g2.push_back(g[i]);
	}
	divide(l,mid,g1);
	divide(mid+1,r,g2);
	p=gg.size();
	for(int i=p-1;i>=0;i--){	
		fa[gg[i].xx]=gg[i].xx;
		dep[gg[i].xx]=gg[i].yy;
	}
	gg.clear();
    cnt=pre;
}
int main()
{
   int n,m,t;
   cin>>n>>m>>t;
   for(int i=1;i<=2*n;i++){
	   fa[i]=i;
	   dep[i]=1;
   }
   vector<pi>g;
   g.clear();
	for(int i=0;i<m;i++){
		scanf("%d%d%d%d",&pp.u,&pp.v,&pp.l,&pp.r);
		if(pp.l==pp.r) continue;
		pp.r--;
		g.push_back(pp);
	}
    cnt=n;
	divide(0,t-1,g);
   	for(int i=0;i<t;i++){
		if(ans[i]) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值