[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< ...
随机推荐
- 【题解】回文串 APIO 2014 BZOJ 3676 COGS 1985 Manacher+后缀数组+二分
这题可以用回文自动机来做,但是我并没有学,于是用Manacher+SA的做法O(nlogn)水过 首先,看到回文串就能想到用Manacher 同样还是要利用Manacher能不重复不遗漏地枚举每个回文 ...
- 000 Python常识与快捷键(未完)
1.Python控制台IDLE的快捷键 Alt + N :返回开始输入的第一条语句 Alt + P :返回刚刚输入的上一条语句 Tab:制表符,用于缩进或补全内容,是Python语法格式的灵魂,作用涵 ...
- Leetcode 138. 复制带随机指针的链表
1.题目要求 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 2.解题思路 (1)笔试思路(求速度,拿分数):使用哈希表 /* ...
- Iterator与ListIterator的区别
Iterator与ListIterator 相同点:(1)两者都是fail-fast机制,都是作为内部类实现的. 区别:二者的区别主要是功能上的: (1)Iterator实现了接口Iterator,属 ...
- 跨域共享cookie和跨域共享session
转载自:http://blog.csdn.net/ahhsxy/article/details/7356128 这里所说的跨域,是指跨二级域名,而且这些域名对应的应用都在同一个app上, 比如我有以下 ...
- 更改本地hosts文件
在 C:\Windows\System32\drivers\etc 下更改 hosts 文件 127.0.0.1 www.baidu.com 这样访问 www.baidu.com 这个地址,其实是访问 ...
- 2050年这些职业将逐渐被AI(人工智能)取代
耳熟能详的人工智能 深蓝Deep Blue是美国IBM公司生产的一台超级国际象棋电脑,重1270公斤,有32个大脑(微处理器),每秒钟可以计算2亿步."深蓝”输入了一百多年来优秀棋手的对 ...
- 常见的Shell
上面提到过,Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本. Unix/Linux上常见的Shell脚本解释器有bash.sh.csh.ksh等,习惯上把它们称作一种Shell.我们常说 ...
- Super A^B mod C (快速幂+欧拉函数+欧拉定理)
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1759 题目:Problem Description Given A,B,C, You should quick ...
- 关于auto-keras训练cnn模型
# 我在训练自己的人脸分类模型的时候发现图片的维度不能太高,经过很多次测试过后觉得一般人脸图片分为28*28大小训练的效果比较好.建议在使用其训练自己的物体识别模型的时候,尽量把图片压缩到28*28# ...