首先我们要知道,怎么去维护一个是否是二分图
二分图的充要条件:点数>=2且无奇环
重点就是不存在奇环,怎么做呢
考虑随便维护一个图的生成树,不难发现,如果一条边加入后,形成奇环的话就不是二分图
否则的话,我们可以无视这条边,因为如果之后再新加入一条边和这条边形成了一个奇环
那么新加入的边一定和原来生成树上的边也能形成奇环
所以我们直接维护一棵生成树即可
然后裸的想法就来了:上lct,维护以离开时间为边权的最大生成树,每次加边弹出环上最早离开的边
然后还是那句话:cdq大法好
我们可以对时间线分治,考虑每条边对应时间段的影响
这样就只有加边而不用删边了,我们可以用并查集维护
然而应该怎么用并查集维护路径的奇偶性呢?方法是膜拜popoqqq的程序的,我简单说明一下
我们给每个点一个权值c,我们定义一个点i到并查集根的权值c的xor和(不包括根)为d[i]
定义两点间路径奇偶性为dis(x,y)=d[x] xor d[y]
当加入一条边x-y且x、y不连通时,假设p[x]是x所在并查集的根,并且我们现在把x所在集合并到y所在集合下
我们就令c[p[x]]=d[x] xor d[y] xor 1(d[]为加入这条边之前的值)
这个操作的保证了每个点权值最多被赋值一次
上述做法为什么能求出两点间路径长的奇偶性呢?我们来证明一下
首先是有边直接相连的两个点x,y,根据A xor B xor B=1的性质
可得dis(x,y)=d[x](加入边之前的) xor d[y] xor c[p[x]](加入边之前的)=d[x] xor d[x] xor d[y] xor d[y] xor 1=1
并且以后再加入别的边改变并查集后,dis(x,y)仍然为1(还是可以通过xor性质得知)
对于没有边直接连的两点x,y,我们只要证明dis(x,y)=dis(po[x],y) xor 1 即可(po[x]为x的一个邻居)
根据定义可得dis(x,y)=d[x] xor d[y] xor d[po[x]] xor d[po[x]]=dis(x,po[x]) xor dis(po[x],y)=1 xor dis(po[x],y)
所以通过上述方法,我们可以用并查集维护路径长的奇偶性
其他与bzoj3237的处理方法有些类似,并不需要可持久化,只需要栈来恢复即可
1 type node=record 2 x,y,s,t:longint; 3 end; 4 5 var c,d,fa:array[0..100010] of longint; 6 e:array[0..200010] of node; 7 te:array[0..300010*20] of node; 8 st:array[0..300010*20] of longint; 9 ans:array[0..100010] of boolean; 10 en,top,t,n,m,len,i,x,y,a,b:longint; 11 12 procedure swap(var a,b:longint); 13 var c:longint; 14 begin 15 c:=a; 16 a:=b; 17 b:=c; 18 end; 19 20 function getf(x:longint):longint; 21 begin 22 while fa[x]<>x do x:=fa[x]; //路径压缩是均摊,所里这里不需要 23 exit(fa[x]); 24 end; 25 26 function dis(x:longint):longint; 27 begin 28 dis:=0; 29 while fa[x]<>x do 30 begin 31 dis:=dis xor c[x]; 32 x:=fa[x]; 33 end; 34 end; 35 36 procedure union(x,y,w:longint); 37 begin 38 if d[x]>d[y] then swap(x,y); //按深度合并 39 fa[x]:=y; 40 inc(en); 41 st[en]:=x; 42 c[x]:=w; 43 if d[x]=d[y] then 44 begin 45 inc(en); 46 st[en]:=-y; 47 inc(d[y]); 48 end; 49 end; 50 51 procedure rebuild(be:longint); 52 var x:longint; 53 begin 54 while be<>en do //两种情况的恢复 55 begin 56 x:=st[en]; 57 if x<0 then 58 dec(d[-x]) 59 else begin 60 fa[x]:=x; 61 c[x]:=0; 62 end; 63 dec(en); 64 end; 65 end; 66 67 procedure add(x,y,a,b:longint); 68 begin 69 inc(len); 70 e[len].x:=x; 71 e[len].y:=y; 72 e[len].s:=a; 73 e[len].t:=b; 74 end; 75 76 procedure cdq(m,l,r:longint); 77 var mid,x,y,w,be,j,dow:longint; 78 begin 79 be:=en; 80 mid:=(l+r) shr 1; 81 for i:=1 to m do 82 if (e[i].s=l) and (e[i].t=r) then 83 begin 84 x:=getf(e[i].x); 85 y:=getf(e[i].y); 86 w:=dis(e[i].x) xor dis(e[i].y) xor 1; 87 if x<>y then union(x,y,w) 88 else if w=1 then 89 begin 90 for j:=l to r do 91 ans[j]:=false; 92 rebuild(be); 93 exit; 94 end; 95 end; 96 if l=r then ans[l]:=true 97 else begin 98 len:=0; 99 dow:=top; 100 for i:=1 to m do //划分边集 101 begin 102 if (e[i].s=l) and (e[i].t=r) then continue; 103 inc(top); 104 te[top]:=e[i]; 105 if e[i].t<=mid then 106 begin 107 inc(len); 108 e[len]:=e[i]; 109 end 110 else if e[i].s<=mid then 111 add(e[i].x,e[i].y,e[i].s,mid); 112 end; 113 cdq(len,l,mid); 114 len:=0; 115 for i:=top downto dow+1 do 116 if te[i].s>mid then 117 begin 118 inc(len); 119 e[len]:=te[i]; 120 end 121 else if te[i].t>mid then 122 add(te[i].x,te[i].y,mid+1,te[i].t); 123 top:=dow; 124 cdq(len,mid+1,r); 125 end; 126 rebuild(be); 127 end; 128 129 begin 130 readln(n,m,t); 131 for i:=1 to m do 132 begin 133 readln(x,y,a,b); 134 inc(a); 135 if a>b then continue; 136 add(x,y,a,b); 137 end; 138 for i:=1 to n do 139 begin 140 fa[i]:=i; 141 d[i]:=1; 142 end; 143 cdq(m,1,t); 144 for i:=1 to t do 145 if ans[i] then writeln('Yes') else writeln('No'); 146 end.