支持加边和删边的二分图判定,分治并查集水之(表示我的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. [LeetCode] Triangle 三角形

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...

  2. [LeetCode] Populating Next Right Pointers in Each Node 每个节点的右向指针

    Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *nex ...

  3. [LeetCode] Partition List 划分链表

    Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...

  4. Zabbix2.4.7源码安装手册

    一.安装Apache Server 注:使用root安装后,变更拥有者为your-user 1 安装环境 系统: CentOS release 6.6 软件: httpd-2.2.31 2 安装步骤 ...

  5. Shell命令_smem

    监控各个进程.用户的内存使用情况 基础条件:需要安装yum工具 centos 7.0 1.安装smem [root@VM_31_182_centos src]# yum install smem py ...

  6. 常用jQuery 方法

    //强制给数字补全小数点 function toDecimal2(x) { var f = parseFloat(x); if(isNaN(f)) { return false; } var f = ...

  7. javascipt的【函数表达式】

    函数表达式 在编程时,我们可以看到不管是什么类库,jquery也好,zepto也好,都会用到大量的命名函数和匿名函数表达式,本节点就是为了弄懂为何会有这些函数表达式,以及在什么情况下会使用到这些表达式 ...

  8. Leetcode 259. 3Sum Smaller

    class Solution(object): def threeSumSmaller(self, nums, target): """ :type nums: List ...

  9. Boost.Python简介

    Boost.Python简单概括:是Boost库的一部分:用来在C++代码中调用python代码以及在Python代码中调用C++代码,并且避免用户直接操作指针. 以下内容搬运自:https://wi ...

  10. javascript操作字符串的方法

    string.indexOf()//返回字符串中第一个与给定子串匹配的子串序号字符串的IndexOf()方法搜索在该字符串上是否出现了作为参数传递的字符串,如果找到字符串,则返回字符的起始位置 (0表 ...