[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< ...
随机推荐
- BAT-Python面试题
Python语言特性 1 Python的函数参数传递 看两个如下例子,分析运行结果: 代码一: a = 1 def fun(a): a = 2 fun(a) print(a) # 1 代码二: a = ...
- 转ajax的jsonp的文章
转:http://justcoding.iteye.com/blog/1366102/ Js是不能跨域请求.出于安全考虑,js设计时不可以跨域. 什么是跨域: 1.域名不同时. 2.域名相同,端口不同 ...
- stout代码分析之七:Result类
Result类似于Option和Try类的组合,内部有三种状态 enum State { SOME, NONE, ERROR }; SOME表示Result对象有值 NONE表示Result对象值为空 ...
- POJ 3254 状态压缩 DP
B - Corn Fields Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:65536KB ...
- cin.get()、流和缓冲区
大家好,这是我在CSDN的第一篇博客.我是一名学习GIS专业的大学生.我从小开始喜欢编程,可是到现在编程水平却长进不大,依然是菜鸟一个.究其原因,虽然这些年乱七八糟的东西学过不少,但是总的来说还是基础 ...
- 二叉树系列 - [LeetCode] Symmetric Tree 判断二叉树是否对称,递归和非递归实现
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). For e ...
- 概率dp+期望dp 题目列表(一)
表示对概率和期望还不是很清楚定义. 目前暂时只知道概率正推,期望逆推,然后概率*某个数值=期望. 为什么期望是逆推的,例如你求到某一个点的概率我们可以求得,然后我们只要运用dp从1~n每次都加下去就好 ...
- PowerDesigner16 修改表或表的字段Name的时候不让Code不自动跟着变
在修改表或表的字段Name的时候不让Code不自动跟着变,设置如下: tools-> General Options-> Dialog 去掉勾选 Name To Code mirror ...
- vs 自定义插件(扩展工具)
此篇仅仅是因为好奇,实现的是完全没有价值的东西,当然,通过此篇的尝试,后续可以在适当的场景,深入的研究Visual Studio自定义插件的应用. 实现功能如下: 在鼠标选中的地方,显示一下创建人,创 ...
- 高精度模板_C++
高精度压位,压9位 read:读入 write:输出 copy:赋值 change:交换 empty:清0 cmp:比较大小,相当于小于号 plus:加法 dec:减法 multy:乘法 除法实在不会 ...