[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< ...
随机推荐
- mybatis生成的pojo 中的属性或方法不够我们当做dto使用时
我们在写代码的时候,如果一个 mybatis生成的pojo 中的属性或方法不够我们使用(当做dto和前台交互)时,我们有两种方法: 第一: 直接在 原 pojo 中增加属性或者方法 第二:我们可以再写 ...
- UVA11426
链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=26&page ...
- shell 将字符串作为变量名并打印
使用shell的eval实现此功能.代码如下: #!/bin/sh IP9="127.0.0.1" i=9 eval echo \$IP${i} #!/bin/sh WEBIP0= ...
- vijos 1426 背包+hash
背景 北京奥运会开幕了,这是中国人的骄傲和自豪,中国健儿在运动场上已经创造了一个又一个辉煌,super pig也不例外……………… 描述 虽然兴奋剂是奥运会及其他重要比赛的禁药,是禁止服用的.但是运动 ...
- 【设计模式】 模式PK:策略模式VS状态模式
1.概述 行为类设计模式中,状态模式和策略模式是亲兄弟,两者非常相似,我们先看看两者的通用类图,把两者放在一起比较一下. 策略模式(左)和状态模式(右)的通用类图. 两个类图非常相似,都是通过Cont ...
- Linux系统基本网络配置之ifconfig命令
Linux系统基本网络配置之ifconfig命令 一.Linux系统的网络配置基本包括:网络IP的配置.网关路由的配置.主机DNS的配置.主机名的配置等,本篇注重介绍网络IP的配置. 二.Linux系 ...
- vs 自定义插件(扩展工具)
此篇仅仅是因为好奇,实现的是完全没有价值的东西,当然,通过此篇的尝试,后续可以在适当的场景,深入的研究Visual Studio自定义插件的应用. 实现功能如下: 在鼠标选中的地方,显示一下创建人,创 ...
- iOS 时间转换
#pragma mark - 获取当前时间戳 -(NSString *)getTimeSp{ NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:]; ...
- 2017 JAVA神器 Btrace详细介绍
官网:https://github.com/btraceio/btrace 下载:https://github.com/btraceio/btrace/releases/tag/v1.3.9 文档:h ...
- [bzoj4567][Scoi2016]背单词-Trie+贪心+模型转化
Brief Description 给你N个互不相同的字符串,记\(S_i\)为第i个字符串,现在要求你指定N个串的出现顺序,我们用\(V_i\)表示第i个字符串是第几个出现的,则V为1到N的一个排列 ...