支持加边和删边的二分图判定,分治并查集水之(表示我的LCT还很不熟……仅仅停留在极其简单的模板水平)。

由于是带权并查集,并且不能路径压缩,所以对权值(到父亲距离的奇偶性)的维护要注意一下。

有一个小优化:如果当前图已经不是二分图就不再继续dfs线段树,直接把区间内的每个答案设为No后回溯即可。

这次写了个按size合并,不过随机合并比按size合并还快一点是什么鬼……

按size合并的代码:

/**************************************************************
Problem: 4025
User: hzoier
Language: C++
Result: Accepted
Time:13616 ms
Memory:39288 kb
****************************************************************/ #include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=;
void addedge(int,int,int);
void solve(int,int,int);
bool mergeset(int,int,vector<int>&);
void cut(int);
int prt[maxn],size[maxn];
bool d[maxn]={false};
int n,m,e,x,y,s,t;
vector<int>u[maxn<<],v[maxn<<];
int main(){
scanf("%d%d%d",&n,&e,&m);
for(int i=;i<=n;i++){
prt[i]=i;
size[i]=;
}
while(e--){
scanf("%d%d%d%d",&x,&y,&s,&t);
s++;
addedge(,m,);
}
solve(,m,);
return ;
}
void addedge(int l,int r,int rt){
if(s<=l&&t>=r){
u[rt].push_back(x);
v[rt].push_back(y);
return;
}
int mid=(l+r)>>;
if(s<=mid)addedge(l,mid,rt<<);
if(t>mid)addedge(mid+,r,rt<<|);
}
void solve(int l,int r,int rt){
vector<int>stk;
bool ok=true;
for(int i=;i<(int)u[rt].size();i++)if(mergeset(u[rt][i],v[rt][i],stk)){
for(int j=l;j<=r;j++)printf("No\n");
ok=false;
break;
}
if(ok){
if(l==r)printf("Yes\n");
else{
int mid=(l+r)>>;
solve(l,mid,rt<<);
solve(mid+,r,rt<<|);
}
}
if(!stk.empty())for(int i=(int)stk.size()-;i>=;i--)cut(stk[i]);
}
bool mergeset(int x,int y,vector<int>&a){
bool dx=false,dy=false;
int rx=x,ry=y;
while(prt[rx]!=rx){
dx^=d[rx];
rx=prt[rx];
}
while(prt[ry]!=ry){
dy^=d[ry];
ry=prt[ry];
}
if(rx==ry)return dx==dy;
if(size[rx]>size[ry])swap(rx,ry);
prt[rx]=ry;
size[ry]+=size[rx];
d[rx]=dx==dy;
a.push_back(rx);
return false;
}
void cut(int x){
int y=prt[x];
while(prt[y]!=y){
size[y]-=size[x];
y=prt[y];
}
size[y]-=size[x];
prt[x]=x;
d[x]=false;
}

随机合并的代码(其实两份代码差别并不大):

 /**************************************************************
Problem: 4025
User: hzoier
Language: C++
Result: Accepted
Time:13104 ms
Memory:38896 kb
****************************************************************/ #include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int randint(){
static int a=,b=,c=,x=,p=;
x=a*x*x+b*x+c;x%=p;
return x<?(x=-x):x;
}
const int maxn=;
void addedge(int,int,int);
void solve(int,int,int);
bool mergeset(int,int,vector<int>&);
int prt[maxn];
bool d[maxn]={false};
int n,m,e,x,y,s,t;
vector<int>u[maxn<<],v[maxn<<];
int main(){
scanf("%d%d%d",&n,&e,&m);
for(int i=;i<=n;i++)prt[i]=i;
while(e--){
scanf("%d%d%d%d",&x,&y,&s,&t);
s++;
addedge(,m,);
}
solve(,m,);
return ;
}
void addedge(int l,int r,int rt){
if(s<=l&&t>=r){
u[rt].push_back(x);
v[rt].push_back(y);
return;
}
int mid=(l+r)>>;
if(s<=mid)addedge(l,mid,rt<<);
if(t>mid)addedge(mid+,r,rt<<|);
}
void solve(int l,int r,int rt){
vector<int>stk;
bool ok=true;
for(int i=;i<(int)u[rt].size();i++)if(mergeset(u[rt][i],v[rt][i],stk)){
for(int j=l;j<=r;j++)printf("No\n");
ok=false;
break;
}
if(ok){
if(l==r)printf("Yes\n");
else{
int mid=(l+r)>>;
solve(l,mid,rt<<);
solve(mid+,r,rt<<|);
}
}
if(!stk.empty())for(int i=(int)stk.size()-;i>=;i--){
prt[stk[i]]=stk[i];
d[i]=false;
}
}
bool mergeset(int x,int y,vector<int>&a){
bool dx=false,dy=false;
int rx=x,ry=y;
while(prt[rx]!=rx){
dx^=d[rx];
rx=prt[rx];
}
while(prt[ry]!=ry){
dy^=d[ry];
ry=prt[ry];
}
if(rx==ry)return dx==dy;
if(randint()&)swap(rx,ry);
prt[rx]=ry;
d[rx]=dx==dy;
a.push_back(rx);
return false;
}

感觉越来越忧伤,却没有办法排解,唉……

bzoj4025 二分图的更多相关文章

  1. BZOJ4025 二分图 分治 并查集 二分图 带权并查集按秩合并

    原文链接http://www.cnblogs.com/zhouzhendong/p/8683831.html 题目传送门 - BZOJ4025 题意 有$n$个点,有$m$条边.有$T$个时间段.其中 ...

  2. BZOJ4025 二分图(线段树分治+并查集)

    之前学了一下线段树分治,这还是第一次写.思想其实挺好理解,即离线后把一个操作影响到的时间段拆成线段树上的区间,并标记永久化.之后一块处理,对于某个节点表示的时间段,影响到他的就是该节点一直到线段树根的 ...

  3. [BZOJ4025]二分图(线段树分治,并查集)

    4025: 二分图 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2191  Solved: 800[Submit][Status][Discuss] ...

  4. [bzoj4025]二分图_LCT

    二分图 bzoj-4025 题目大意:给定一个n个节点的图,m条边,每条边有一个产生时间和一个删除时间,询问所有时间点是否是连通图. 注释:$1\le n\le 10^5$,$1\le m\le 2\ ...

  5. bzoj4025二分图(线段树分治 并查集)

    /* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...

  6. bzoj4025 二分图 [分治,并查集]

    传送门 思路 是二分图的充要条件:图没有奇环. 考虑按时间分治,用可撤销并查集维护点到根的距离. 仍然可以用一个小trick把两点连边变成根连边,可以看这里. 每次连边时若不连通则连上,否则判一下有没 ...

  7. bzoj4025: 二分图 lct

    题意:带增删边的查询二分图 题解:因为二分图肯定带奇环,lct维护,每次要加入一条边之前判断会不会构成环,如果会就把最先会删除的边删掉,然后如果是奇环就打个标记,然后把奇环数++,删除的时候,把标记删 ...

  8. 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)

    传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...

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

    Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考考你. Input ...

随机推荐

  1. 【原创】Chrome最新版(53-55)再次爆出BUG!

    前言 今年十月份,我曾发布一篇文章<Chrome53 最新版惊现无厘头卡死 BUG!>,不过那个BUG在最新的 Chrome 54 中已经修正. 而今天即将发布的Chrome弱智BUG: ...

  2. UDP通信

    package com.slp; import java.io.IOException; import java.net.DatagramPacket; import java.net.Datagra ...

  3. WinHttp

    using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System. ...

  4. Redis中connect与pconnect区别?

    1.首先先介绍下connect和pconnect的区别. connect:脚本结束之后连接就释放了. 2.pconnect:脚本结束之后连接不释放,连接保持在php-fpm进程中. 所以使用pconn ...

  5. 把url参数转化成一个对象返回

    var readUrlToParams = function () { var url = location.href; var nameValue; var paraString = url.sub ...

  6. android获取位置location为null的问题

      12:38:542016-12-23 很多人经常遇到这种问题,主要是获取到位置的信息为null,第一个主要要有权限 <uses-permission android:name="a ...

  7. BZOJ-2127-happiness(最小割)

    2127: happiness(题解) Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1806  Solved: 875 Description 高一 ...

  8. 批量 ping 测试脚本

    是否会使用 vpn 工作,已经成为魔法师和麻瓜之间最重要的区分.使用 vpn 工作,也产生了其它一些奇奇怪怪的问题,比如,选择 vpn 服务器. 你要测试哪个 vpn 离你最近. 所以,就有了下面的脚 ...

  9. Java 抽象类与接口

    接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是 Java 语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予 Java 强大的面向对象的能力.他们两者之间对 ...

  10. Redis常用命令(String数据类型)

    一.概述:      字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中 ...