支持加边和删边的二分图判定,分治并查集水之(表示我的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. 基于C/S架构的3D对战网络游戏C++框架 _01服务器端与客户端需求分析

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  2. 使用Minicom基于串口调试HiKey

    虽然通过adb shell调试方便,但是有些时候不得不借助于串口进行调试,比如测试suspend to ram之类的功能时,adb服务被关闭. 同时在minicom中也可以进入shell,进行操作. ...

  3. hdu3714 三分找最值

    Error Curves Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  4. sql server 取多个数字或者时间的最大值

    SELECT MAX(b.a) from ( select distinct * from (values (1), (1), (1), (2), (5), (1), (6)) as Y(a) ) a ...

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

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

  6. COGS2531. [HZOI 2016]函数的美 打表+欧拉函数

    题目:http://cogs.pw/cogs/problem/problem.php?pid=2533 这道题考察打表观察规律. 发现对f的定义实际是递归式的 f(n,k) = f(0,f(n-1,k ...

  7. RabbitMQ 集群

    集群 消息队列要想在项目里用的溜,还是要做集群.稳定可靠 但是如果只有一个服务器的话 崩溃的话还是会懵逼的.所以集群化让崩溃的损失降到最小. 在这里我要用三台机器来做集群,不同系统在一起集合才叫酸爽 ...

  8. SVN 错误 Access to SVN Repository Forbidden的原因及解决方法

    原创文章,转载请注明出处:http://www.cnblogs.com/baipengzhan/p/SVN_Access_to_SVN_Repository_Forbidden.html   当我们新 ...

  9. UML(Unified Model Language)统一建模语言

    一.九种图 二.类间关系 一.UML中的九种图 1.用例图(use case diagrams) [概念]描述用户需求,从用户的角度描述系统的功能 [描述方式]椭圆表示某个用例:人形符号表示角色 [目 ...

  10. NOIP2016题解

    D1T1:把方向和朝向异或一下,在mod n意义下+1s或-1s. #include<cstdio> const int N=1e5+5; int n,m,j,k,v,s[N]; char ...