bzoj4025: 二分图

4025: 二分图

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1127  Solved: 420
[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。
 
题解
  我们想象对时间轴建一颗线段树,然后对于每一条边有个存在区间,想象线段树区间覆盖。我们从顶走到底的一个点的话,把所有覆盖路径上节点的边都拿出来处理,这样就得到了这个时间点的状态。我们用这样的思想对时间轴进行分治,对于当前处理的某个时间段,首先把完全覆盖这个时间段[l,r]的边给处理一下,然后把开始时间<=mid的找出来递归处理[l,mid],再把结束时间>=mid+1的拿出来递归处理[mid+1,r]
  具体实现的方法是可撤销带权并查集,权是到根的路径长度的奇偶,每次处理完一个区间,就把这个区间所有的合并操作全部撤销……这个好像挺简单的网上应该都有……有点像是ahoi2013的某道题。
  1 program j01;
  2 const maxn=100086;
  3 type edge=record u,v,st,ed:longint; end;
  4 var e:array[0..2*maxn]of edge;
  5     st:array[0..2*maxn]of longint;
  6     fa,d:array[0..maxn]of longint;
  7     a:array[0..maxn]of boolean;
  8     n,m,t,i,top:longint;
  9  
 10 procedure swap(var a,b:edge);
 11 var c:edge;
 12 begin
 13   c:=a;a:=b;b:=c;
 14 end;
 15  
 16 procedure swap(var a,b:longint);
 17 var c:longint;
 18 begin
 19   c:=a;a:=b;b:=c;
 20 end;
 21  
 22 function ic(var a:longint):longint;
 23 begin
 24   inc(a);exit(a);
 25 end;
 26  
 27 function de(var a:longint):longint;
 28 begin
 29   de:=a;dec(a);
 30 end;
 31  
 32 function find(i:longint):longint;
 33 begin
 34   while fa[i]<>i do i:=fa[i];exit(i);
 35 end;
 36  
 37 function dep(i:longint):boolean;
 38 begin
 39   dep:=false;
 40   while fa[i]<>i do
 41   begin
 42     dep:=dep xor a[i];i:=fa[i];
 43   end;
 44 end;
 45  
 46 procedure union(u,v:longint;dd:boolean);
 47 begin
 48   if d[u]>d[v] then swap(u,v);
 49   if d[u]=d[v] then
 50   begin
 51     st[ic(top)]:=-v;inc(d[v]);
 52   end;
 53   st[ic(top)]:=u;fa[u]:=v;
 54   a[u]:=dd;
 55 end;
 56  
 57 procedure resume(now:longint);
 58 begin
 59   while top>now do
 60   begin
 61     if st[top]<0 then dec(d[-st[top]]) else
 62     begin
 63       fa[st[top]]:=st[top];a[st[top]]:=false;
 64     end;
 65     dec(top);
 66   end;
 67 end;
 68  
 69 procedure solve(l,r,m:longint);
 70 var mid,i,j,now,fx,fy:longint;dd:boolean;
 71 begin
 72   now:=top;mid:=(l+r)div 2;
 73   i:=1;
 74   while i<=m do
 75   begin
 76     if(e[i].st<=l)and(r<=e[i].ed)then
 77     begin
 78       fx:=find(e[i].u);fy:=find(e[i].v);
 79       dd:=not(dep(e[i].u) xor dep(e[i].v));
 80       if fx<>fy then union(fx,fy,dd) else
 81       begin
 82         if dd then
 83         begin
 84           for j:=l to r do writeln('No');
 85           resume(now);
 86           exit;
 87         end;
 88       end;
 89       swap(e[de(i)],e[de(m)]);
 90     end;
 91     inc(i);
 92   end;
 93   if l=r then
 94   begin
 95     writeln('Yes');resume(now);exit;
 96   end;
 97   i:=1;j:=m;
 98   while i<=j do
 99   begin
100     if e[i].st>mid then swap(e[de(i)],e[de(j)]);
101     inc(i);
102   end;
103   solve(l,mid,j);
104   i:=1;j:=m;
105   while i<=j do
106   begin
107     if e[i].ed<=mid then swap(e[de(i)],e[de(j)]);
108     inc(i);
109   end;
110   solve(mid+1,r,j);
111   resume(now);
112 end;
113  
114 begin
115   readln(n,m,t);
116   for i:=1 to n do
117   begin
118     fa[i]:=i;a[i]:=false;d[i]:=1;
119   end;
120   i:=1;
121   while i<=m do
122   begin
123     readln(e[i].u,e[i].v,e[i].st,e[i].ed);
124     inc(e[i].st);
125     if e[i].st>e[i].ed then
126     begin
127       dec(i);dec(m);
128     end;
129     inc(i);
130   end;
131   top:=0;
132   solve(1,t,m);
133 end.
View Code

 

posted @ 2017-03-04 23:55  OldJang  阅读(347)  评论(0编辑  收藏  举报