[BZOJ4025] 二分图 LCT/(线段树分治+并查集)
4025: 二分图
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 2667 Solved: 989
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1 2 0 2
2 3 0 3
1 3 1 2
Sample Output
No
Yes
HINT
Source
LCT做法
其实就是求是否有奇环。先求出最小生成树,随后根据非树边两点间的距离得出是否有奇环。
lct维护以边消失时间为权值的最大生成树。这样可以保证所有已经进入集合的非树边都不会从集合中出来再次成为树边。
从小到达枚举时间进行加边和删边。
加边判奇环,更新最大生成树和集合.
删边如果是最大生成树里的边就在lct中删掉。否则仅在集合中删掉即可。
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 400001
using namespace std;
inline int read() {
char ch=getchar();int x=,f=;
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-;
for(;isdigit(ch);ch=getchar()) x=x*+ch-'';
return x*f;
}
int n,m,T,ont[maxn*],jh[maxn*],tot,val[maxn*];
struct Edge {
int to[maxn*],nxt[maxn*],head[maxn*],cnt;
Edge(){memset(head,-,sizeof(head));cnt=;}
void add(int u,int v) {to[cnt]=v;nxt[cnt]=head[u];head[u]=cnt++;}
}e1,e2;
struct ASK {int u,v,w;}a[maxn*];
struct LCT {
struct Data {
int son[],sz,fa,rev,mn;
}t[maxn*];
bool isrt(int x) {return t[t[x].fa].son[]!=x&&t[t[x].fa].son[]!=x;}
void pushdown(int x) {
if(t[x].rev) {
swap(t[x].son[],t[x].son[]);
t[t[x].son[]].rev^=;t[t[x].son[]].rev^=;
t[x].rev=;
}
}
void pushup(int x) {
t[x].sz=t[t[x].son[]].sz+t[t[x].son[]].sz+(x>n);
t[x].mn=x;
if(val[t[t[x].son[]].mn]<val[t[x].mn]) t[x].mn=t[t[x].son[]].mn;
if(val[t[t[x].son[]].mn]<val[t[x].mn]) t[x].mn=t[t[x].son[]].mn;
}
void rotate(int x) {
int y=t[x].fa,z=t[y].fa;
bool l=(t[y].son[]==x),r=l^;
if(!isrt(y)) t[z].son[t[z].son[]==y]=x;
t[x].fa=z;t[y].fa=x;t[t[x].son[r]].fa=y;
t[y].son[l]=t[x].son[r];t[x].son[r]=y;
pushup(y);pushup(x);
}
void push(int x) {
if(!isrt(x)) push(t[x].fa);
pushdown(x);
}
void splay(int x) {
push(x);
while(!isrt(x)) {
int y=t[x].fa,z=t[y].fa;
if(!isrt(y)) {
if(t[y].son[]==x^t[z].son[]==y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x) {for(int pre=;x;pre=x,x=t[x].fa) {splay(x),t[x].son[]=pre;pushup(x);}}
void makert(int x) {access(x);splay(x);t[x].rev^=;}
void link(int x,int y) {makert(x);t[x].fa=y;}
void cut(int x,int y) {makert(x);access(y);splay(y);t[y].son[]=t[x].fa=;}
int find(int x) {access(x);splay(x);while(t[x].son[]) x=t[x].son[];return x;}
}lct;
void insert(int x,int u,int v,int w) {
if(u==v) {jh[x]=;tot++;return;}
if(lct.find(u)!=lct.find(v)) { ont[x]=;lct.link(u,n+x);lct.link(v,n+x);
}
else {
lct.makert(v);lct.access(u);lct.splay(u);int tmp=lct.t[u].mn-n;
if(a[tmp].w<a[x].w) {
if(!(lct.t[u].sz&)) {jh[tmp]=;tot++;}
lct.cut(a[tmp].u,tmp+n);lct.cut(a[tmp].v,tmp+n);
lct.link(u,n+x);lct.link(v,n+x);
ont[tmp]=;ont[x]=;
}
else {
if(!(lct.t[u].sz&)) {jh[x]=;tot++;}
}
}
}
void del(int x,int u,int v,int w) {
if(ont[x]) {lct.cut(u,x+n);lct.cut(v,x+n);}
else if(jh[x]) tot--;
}
int main() {
n=read(),m=read(),T=read();
memset(val,,sizeof(val));
for(int i=;i<=n;i++) lct.t[i].mn=i;
for(int i=;i<=m;i++) {
a[i].u=read(),a[i].v=read();int s=read(),t=read();
e1.add(s,i);e2.add(t,i);a[i].w=t;lct.t[n+i].sz=;lct.t[n+i].mn=n+i;val[n+i]=t;
}
for(int i=;i<T;i++) {
for(int j=e1.head[i];j>=;j=e1.nxt[j]) {
int to=e1.to[j];
insert(to,a[to].u,a[to].v,a[to].w);
}
for(int j=e2.head[i];j>=;j=e2.nxt[j]) {
int to=e2.to[j];
del(to,a[to].u,a[to].v,a[to].w);
}
if(!tot) printf("Yes\n");
else printf("No\n");
}
return ;
}
/*
45365
57727
*/
[BZOJ4025] 二分图 LCT/(线段树分治+并查集)的更多相关文章
- 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)
传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...
- BZOJ4025 二分图(线段树分治+并查集)
之前学了一下线段树分治,这还是第一次写.思想其实挺好理解,即离线后把一个操作影响到的时间段拆成线段树上的区间,并标记永久化.之后一块处理,对于某个节点表示的时间段,影响到他的就是该节点一直到线段树根的 ...
- bzoj4025二分图(线段树分治 并查集)
/* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...
- BZOJ4025: 二分图【线段树分治】【带撤销的并查集】
Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考考你. Input ...
- BZOJ3237:[AHOI2013]连通图(线段树分治,并查集)
Description Input Output Sample Input 4 5 1 2 2 3 3 4 4 1 2 4 3 1 5 2 2 3 2 1 2 Sample Output Connec ...
- Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)
题面 Bzoj 洛谷 题解 考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治. 具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内 ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)
传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...
- bzoj4025-二分图【线段树分治,并查集】
正题 题目链接:https://darkbzoj.tk/problem/4025 题目大意 \(n\)个点\(m\)条边,每条边会在一个\(T\)以内的时间段内出现,对于任意一个\(T\)以内的时刻求 ...
- BZOJ3237 AHOI2013连通图(线段树分治+并查集)
把查询看做是在一条时间轴上.那么每条边都有几段存在时间.于是线段树分治就好了. 然而在bzoj上t掉了,不知道是常数大了还是写挂了. 以及brk不知道是啥做数组名过不了编译. #include< ...
随机推荐
- 关于web.xml中的<welcome-file-list>中的默认首页资料
关于web.xml中的<welcome-file-list>中的默认首页文件 先看我的配置文件: <welcome-file-list> <welcome-file> ...
- RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件
SIFT源码分析系列文章的索引在这里:RobHess的SIFT源码分析:综述 imgfeatures.h中有SIFT特征点结构struct feature的定义,除此之外还有一些特征点的导入导出以及特 ...
- 《python核心编程》读书笔记--第18章 多线程编程
18.1引言 在多线程(multithreaded,MT)出现之前,电脑程序的运行由一个执行序列组成.多线程对某些任务来说是最理想的.这些任务有以下特点:它们本质上就是异步的,需要多个并发事务,各个事 ...
- 使用snmp4j实现Snmp功能(一)
相关链接:Snmp学习笔记使用snmp4j实现Snmp功能(一)使用snmp4j实现Snmp功能(二)使用snmp4j实现Snmp功能(三) 上一篇文章讲了Snmp的一些基本概念(Snmp学习笔记), ...
- HDU 5651 逆元
xiaoxin juju needs help Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/ ...
- OpenCV学习笔记(01)我的第一个OpenCV程序(环境配置)
昨天刚刚考完编译原理,私心想着可以做一些与考试无关的东西了.一直想做和图像处理相关的东西,趁这段时间有空学习一下OpenCV,搭建环境真是一件麻烦的事情,搞了近三个小时终于OK了.先来张图: 大致描述 ...
- bzoj2428 [HAOI2006]均分数据 模拟退火
[HAOI2006]均分数据 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 3434 Solved: 1091[Submit][Status][Dis ...
- [LeetCode] 1. Two Sum ☆
Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...
- Java包名命名规则
1. sun公司建议java包的命名规则为域名的倒写. 比如:sun公司www.sun.com 就用该是com.sun.www 2. indi : 个体项目,指个人发起,但非自己独自完成的项目,可公 ...
- 在此位置打开CMD
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\folder\shell\cmd]@="在此位置打开CMD"[HKE ...