bzoj 4025 二分图

【题目大意】

  有n个点m条边,边会在start时刻出现在end时刻消失,求对于每一段时间,该图是不是一个二分图。

  判断二分图的一个简单的方法:是否存在奇环

  若存在奇环,就不是二分图。

  假设加入一条u->v的边,u,v已经联通,怎么知道是否是一个奇环呢?只需要知道u,v之间的距离就行了。距离为偶数则是一个奇环。

  路径?加边?删边?

  很容易就想到是LCT。

  维护u->v的距离。

  每次加入一条边,就判断是否先前已经联通,否,则家父,若是,就判断u,v之间的距离。

  假若已经构成一个奇环,那么,在这个环的任意一条边都未被删除前,都不是二分图。

  那就在维护一个minv,表示最小的end值。加入一条边构成了环,就删掉最小end值的那条边,加入新边。

  由于是最小值,删掉不会有影响。(最小的end值的那条边肯定是先消失的)

  要把边拆成点,为了记录min值,以及对应的边。

  细节,慢慢处理就好了。(被坑了好久……)

注意:有自环,需特判。

【附上代码】

#include<cstdio>
#include<algorithm> #define imax(a,b) ((a>b)?(a):(b))
#define imin(a,b) ((a<b)?(a):(b)) using namespace std; const int N=100010;
int n,m,T,cnt,len;
struct tree
{
tree *c[2],*f,*pp,*L,*R;
bool flip;
int minv,val,siz;
int d() { return (f->c[1]==this); }
void sc(tree *x,int d) { (c[d]=x)->f=this; }
} nil[N*3],*ro[N*3],*stack[N*3];
struct data { int u,v,start,end; } d[N<<1];
int ans[N]; tree *newtree()
{
nil[++cnt]=nil[0];
return nil+cnt;
} void down(tree *x)
{
if(x==nil) return;
if(x->flip)
{
x->flip=0;
swap(x->c[0],x->c[1]);
if(x->c[0]!=nil) x->c[0]->flip^=1;
if(x->c[1]!=nil) x->c[1]->flip^=1;
}
} void up(tree *x)
{
if(x==nil) return;
x->minv=x->val; x->siz=1;
if(x->c[0]!=nil) x->minv=imin(x->minv,x->c[0]->minv),x->siz+=x->c[0]->siz;
if(x->c[1]!=nil) x->minv=imin(x->minv,x->c[1]->minv),x->siz+=x->c[1]->siz;
} void rotate(tree *x)
{
int d=x->d();
tree *y=x->f;
y->sc(x->c[!d],d);
if(y->f==nil) x->f=nil; else y->f->sc(x,y->d());
x->sc(y,!d);
up(y); up(x);
x->pp=y->pp;
y->pp=nil;
} void splay(tree *x)
{
int hy=1;
stack[hy]=x;
for(;stack[hy]->f!=nil;hy++) stack[hy+1]=stack[hy]->f;
for(;hy;) down(stack[hy]),hy--;
for(tree *y;x->f!=nil;)
{
y=x->f;
if(y->f!=nil)
(x->d()^y->d())?rotate(x):rotate(y);
rotate(x);
}
} void access(tree *x)
{
tree *y=nil;
while(x!=nil)
{
splay(x);
if(x->c[1]!=nil)
{
x->c[1]->f=nil;
x->c[1]->pp=x;
}
x->c[1]=y;
if(y!=nil)
{
y->f=x;
y->pp=nil;
}
up(x);
y=x; x=x->pp;
}
} void evert(tree *x)
{
access(x);
splay(x);
x->flip^=1;
} void link(tree *x,tree *y)
{
evert(y);
y->pp=x;
} void cut(tree *x,tree *y)
{
evert(x);
access(y);
splay(y);
if(y->c[0]!=nil)
{
y->c[0]->f=nil;
y->c[0]=nil;
}
up(y);
} tree *findroot(tree *x)
{
access(x);
splay(x);
while(x->c[0]!=nil)
{
x=x->c[0];
down(x);
}
splay(x);
return x;
} tree *findmin(tree *x,tree *y)
{
evert(x);
access(y);
splay(x); down(x);
len=(x->siz+1)>>1;
int find=x->minv;
for(;;)
{
if(x->val==find) break;
if(x->c[0]!=nil && x->c[0]->minv==find) x=x->c[0];
else x=x->c[1];
down(x);
}
splay(x);
return x;
} bool cmp(data A,data B) { return (A.start<B.start); } int main()
{
scanf("%d%d%d",&n,&m,&T); cnt=0;
nil->val=nil->minv=1e9; nil->siz=0; nil->pp=nil;
nil->f=nil->c[0]=nil->c[1]=nil->L=nil->R=nil;
for(int i=1;i<=m;i++) scanf("%d%d%d%d",&d[i].u,&d[i].v,&d[i].start,&d[i].end);
sort(d+1,d+1+m,cmp);
for(int i=1;i<=n;i++) ro[i]=newtree();
for(int i=1;i<=m;i++)
{
ro[n+i]=newtree();
ro[n+i]->val=d[i].end; ro[n+i]->minv=d[i].end;
ro[n+i]->L=ro[d[i].u]; ro[n+i]->R=ro[d[i].v];
}
for(int i=1;i<=m;i++)
{
if(d[i].u==d[i].v)
{
ans[d[i].start]++; ans[d[i].end]--;
continue;
}
if(findroot(ro[d[i].u])!=findroot(ro[d[i].v]))
{
link(ro[d[i].u],ro[n+i]);
link(ro[n+i],ro[d[i].v]);
}
else
{
tree *getmin=findmin(ro[d[i].u],ro[d[i].v]);
if(d[i].start<getmin->val && (len&1))
{
ans[d[i].start]++;
ans[imin(getmin->val,d[i].end)]--; //重点啊,我就被这里坑了
}
if(d[i].end>getmin->val)
{
cut(getmin,getmin->L);
cut(getmin,getmin->R);
link(ro[d[i].u],ro[n+i]);
link(ro[n+i],ro[d[i].v]);
}
}
}
int yu=0;
for(int i=0;i<T;i++)
{
yu+=ans[i];
if(yu>0) printf("No\n"); else printf("Yes\n");
}
return 0;
}

【其他思路】

  分治+可回溯并查集(就是不带路径压缩的并查集)

  Solve(L,R,S)表示处理L到R这个时间段,有关联的边集为S。

  如果存在L->R的时间段的边,且加入后构成了奇环,那么L->R这段时间都不为二分图,直接退出。

  把边集划分为左右两边,即边与左区间的交集归左边,右边的交集归右边。(是start和end的交集)

  然后先处理左边,再处理右边就行了。

  具体的看这里,我没写cdq分治,这是我同学的

bzoj 4025 二分图 分治+并查集/LCT的更多相关文章

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

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

  2. [BZOJ 4025]二分图(线段树分治+带边权并查集)

    [BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...

  3. bzoj 4025 二分图——线段树分治+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...

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

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

  5. hdu_5354_Bipartite Graph(cdq分治+并查集判二分图)

    题目链接:hdu_5354_Bipartite Graph 题意: 给你一个由无向边连接的图,问对于每一个点来说,如果删除这个点,剩下的点能不能构成一个二分图. 题解: 如果每次排除一个点然后去DFS ...

  6. BZOJ_4025_二分图_线段树按时间分治+并查集

    BZOJ_4025_二分图_线段树按时间分治+并查集 Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简 ...

  7. bzoj 3669: [Noi2014]魔法森林(并查集+LCT)

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

  8. 【CF576E】Painting Edges 线段树按时间分治+并查集

    [CF576E]Painting Edges 题意:给你一张n个点,m条边的无向图,每条边是k种颜色中的一种,满足所有颜色相同的边内部形成一个二分图.有q个询问,每次询问给出a,b代表将编号为a的边染 ...

  9. HDU 3081 Marriage Match II (二分图,并查集)

    HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...

随机推荐

  1. 慕课网中网页定位导航中js相关问题总结

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...

  2. [转]Linux下/proc目录简介

    1. /proc目录Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文 ...

  3. Redux 基础概念

    Redux is a predictable state container for JavaScript apps.,亦即 Redux 希望能提供一个可以预测的 state 管理容器,让开发者可以可 ...

  4. SQL基本操作——declare if lese while

    declare --第一种 declare @i int set @i= (select COUNT(*) from t8) select @i --第二种 declare @i int select ...

  5. Codeforces_731F_(前缀和)

    F. Video Cards time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  6. altera quartus 百度云分享 quartus prime 17.1 16.1 13.0

    quartus prime 17.1 标准版 链接:https://pan.baidu.com/s/10QWejKdDobVxDSqnVPJ0xQ 提取码:hhvj 复制这段内容后打开百度网盘手机Ap ...

  7. iview表单密码自定义验证

    From中定义   ref="passwordForm" 获取dom节点  :model="passwordForm" 关联表单数据对象 :rules=&quo ...

  8. js 字符串,数组扩展

    console.log(Array.prototype.sort)//ƒ substring() { [native code] } console.log(String.prototype.subs ...

  9. Entertainment Box Gym100781E(数据结构+贪心)

    Entertainment Box 题意: 有n个节目,每个节目给出开始时间(st)和结束时间(en): 有k个内存条这k个内存条可以同时存储节目.如果节目j的开始时间stj  大于等于节目i的结束时 ...

  10. HTML学习笔记之标签进阶

    目录 1.框架 2.表单 3.音频 4.视频 5.文档类型 6.头部元素 7.样式 8.脚本 9.实体 1.框架 使用框架允许我们在同一个浏览器窗口中显示多个页面,其中每份 HTML 文档称为一个框架 ...