4025: 二分图

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2191  Solved: 800
[Submit][Status][Discuss]

Description

神犇有一个n个节点的图。因为神犇是神犇,所以在T时间内一些边会出现后消失。神犇要求出每一时间段内这个图是否是二分图。这么简单的问题神犇当然会做了,于是他想考考你。

Input

输入数据的第一行是三个整数n,m,T。
第2行到第m+1行,每行4个整数u,v,start,end。第i+1行的四个整数表示第i条边连接u,v两个点,这条边在start时刻出现,在第end时刻消失。

Output

输出包含T行。在第i行中,如果第i时间段内这个图是二分图,那么输出“Yes”,否则输出“No”,不含引号。

Sample Input

3 3 3
1 2 0 2
2 3 0 3
1 3 1 2

Sample Output

Yes
No
Yes

HINT

样例说明:
0时刻,出现两条边1-2和2-3。
第1时间段内,这个图是二分图,输出Yes。
1时刻,出现一条边1-3。
第2时间段内,这个图不是二分图,输出No。
2时刻,1-2和1-3两条边消失。
第3时间段内,只有一条边2-3,这个图是二分图,输出Yes。
数据范围:
n<=100000,m<=200000,T<=100000,1<=u,v<=n,0<=start<=end<=T。

Source

[Submit][Status][Discuss]

挺妙的思想,线段树不仅仅是一种数据结构,还是一种处理问题的思想,在图论的建图等方面也有用到。

这个方法全称应该叫“线段树对时间CDQ分治”,用于处理有时间参数的修改与询问问题。但是有一个前提,就是一个时间区间的修改可以分成互不影响的两个时间区间的修改,比如这题的边(u,v,start,end)可以分裂为(u,v,start,mid)和(u,v,mid+1,end)。

这题听说LCT可做,但还有一种思路,CDQ(L,R,A)表示询问在[L,R]中,关于这个询问(且还未被处理)的修改集合为A的分治过程。具体流程是:

1.遍历A,对于所有完全包含[L,R]的修改操作进行处理。

2.将A中所有不完全包含[L,R]的修改操作按照线段树的分法分到包含[L,mid]和[mid+1,R]的两个区间中,用集合B和C记录这些修改。

3.分别递归[L,mid]和[mid+1,R],如果L=R则可以直接特判回溯。

4.撤销本层所有操作,保证后续回溯与递归正确进行。

回到这一题,所谓修改就是记录距离的并查集操作(因为判断二分图的方法就是查找里面是否有奇环),所以这里的并查集必须支持撤销,不能路径压缩。总复杂度$O(n\log^2 n)$

 #include<cstdio>
#include<vector>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=;
int n,m,T,u,v,l,r,top;
struct E{int u,v,l,r; bool operator<(const E &a)const{ return (l==a.l)?r<a.r:l<a.l; } };
vector<E> a;
struct P{ int fa,val,sz; }t[N];
struct D{ int x,y; P a,b; }stk[N]; void init(){ rep(i,,n) t[i]=(P){i,,}; }
int find(int x){ while (t[x].fa!=x) x=t[x].fa; return x;}
int dis(int x){
int res=;
while (t[x].fa!=x) res^=t[x].val,x=t[x].fa;
return res;
} void link(int x,int y){
int val=dis(x)^dis(y)^;
x=find(x); y=find(y);
stk[++top]=(D){x,y,t[x],t[y]};
if (t[x].sz>t[y].sz) swap(x,y);
t[x].fa=y; t[x].val=val; t[y].sz+=t[x].sz;
} void recov(int k){ while (top!=k) t[stk[top].x]=stk[top].a,t[stk[top].y]=stk[top].b,top--; } void CDQ(int L,int R,vector<E> &a){
int mid=(L+R)>>,bot=top;
vector<E> b,c;
for (int i=; i<(int)a.size(); i++){
E now=a[i]; int x=now.u,y=now.v;
if (now.l==L && now.r==R){
int p=find(x),q=find(y);
if (p==q){
int val=dis(x)^dis(y);
if (val==){
rep(i,L,R) puts("No");
recov(bot); return;
}
}else link(x,y);
}else if (now.r<=mid) b.push_back(now);
else if (now.l>mid) c.push_back(now);
else b.push_back((E){now.u,now.v,now.l,mid}),c.push_back((E){now.u,now.v,mid+,now.r});
}
if (L==R) puts("Yes"); else CDQ(L,mid,b),CDQ(mid+,R,c);
recov(bot);
} int main(){
freopen("bzoj4025.in","r",stdin);
freopen("bzoj4025.out","w",stdout);
scanf("%d%d%d",&n,&m,&T);
rep(i,,m){
scanf("%d%d%d%d",&u,&v,&l,&r); l++;
if (l<=r) a.push_back((E){u,v,l,r});
}
init(); CDQ(,T,a);
return ;
}

[BZOJ4025]二分图(线段树分治,并查集)的更多相关文章

  1. bzoj4025二分图(线段树分治 并查集)

    /* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...

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

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

  3. BZOJ4025 二分图(线段树分治+并查集)

    之前学了一下线段树分治,这还是第一次写.思想其实挺好理解,即离线后把一个操作影响到的时间段拆成线段树上的区间,并标记永久化.之后一块处理,对于某个节点表示的时间段,影响到他的就是该节点一直到线段树根的 ...

  4. 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 ...

  5. Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)

    题面 Bzoj 洛谷 题解 考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治. 具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内 ...

  6. BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)

    传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...

  7. BZOJ3237 AHOI2013连通图(线段树分治+并查集)

    把查询看做是在一条时间轴上.那么每条边都有几段存在时间.于是线段树分治就好了. 然而在bzoj上t掉了,不知道是常数大了还是写挂了. 以及brk不知道是啥做数组名过不了编译. #include< ...

  8. BZOJ4025 二分图 线段树分治、带权并查集

    传送门 如果边不会消失,那么显然可以带权并查集做(然后发现自己不会写带权并查集) 但是每条边有消失时间.这样每一条边产生贡献的时间对应一段区间,故对时间轴建立线段树,将每一条边扔到线段树对应的点上. ...

  9. bzoj4025-二分图【线段树分治,并查集】

    正题 题目链接:https://darkbzoj.tk/problem/4025 题目大意 \(n\)个点\(m\)条边,每条边会在一个\(T\)以内的时间段内出现,对于任意一个\(T\)以内的时刻求 ...

随机推荐

  1. HihoCoder 重复旋律

    あの旋律を何度も繰り返しでも.あの日見た光景を再現できない 无论将那段旋律重复多少次,也无法重现那一日我们看到的景象 もし切ないならば.時をまきもどしてみるかい? 若是感到惆怅的话,要试着让时光倒流吗 ...

  2. 01背包入门 dp

    题目引入: 有n个重量和价值分别为Wi,Vi的物品.从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中的价值总和的最大值. 分析: 首先,我们用最普通的方法,针对每个物品是否放入背包进行搜索. ...

  3. Sberbank Russian Housing Market比赛总结

    第一次真正意义上参加kaggle比赛,都是工作之余看看别人的kernel,然后整理整理自己的分析代码. 总体来说,本次比赛对我而言更像一个入门比赛,更多的是走走kaggle比赛的整个流程,看看高手们都 ...

  4. Linux 内核通知链随笔【中】【转】

    转自:http://blog.chinaunix.net/uid-23069658-id-4364171.html 关于内核通知链不像Netlink那样,既可以用于内核与用户空间的通信,还能用于内核不 ...

  5. 64_m1

    MAKEDEV-3.24-18.fc26.x86_64.rpm 13-Feb-2017 22:33 101030 MUMPS-5.0.2-8.fc26.i686.rpm 14-Feb-2017 13: ...

  6. webview loadRequest

    // 所构建的NSURLRequest具有一个依赖于缓存响应的特定策略,cachePolicy取得策略,timeoutInterval取得超时值 [self.yourSite loadRequest: ...

  7. nginx配置文件的详细讲解

    user nginx nginx; #定义Nginx运行的用户和用户组worker_processes 1; #nginx进程数,建议设置为等于CPU总核心数worker_rlimit_nofile ...

  8. 循环select查询结果集

    --标记id --每次查询特定列比标记id大的第一条数据, --同时更新标记id,直到查询结果为空 ) set @id='' begin @id=id from T_SGZ where id>@ ...

  9. 如何测试一台主机的IP和端口是否能连通,ping telnet

    通过ping 判断一台主机是否开机. 通过:telnet 121.199.167.99 61616  判断一台主机的端口是否能连通. 本机------本地防火墙-------本地路由器-------- ...

  10. BNU - 49102

    进化之地(Evoland) Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO for ...