• bzoj4025


    首先我们要知道,怎么去维护一个是否是二分图

    二分图的充要条件:点数>=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.
    View Code
  • 相关阅读:
    面向对象 课堂记录
    面向对象10个案例 (来源网络)
    面向对象举例
    面向对象
    36选7
    Android ImageView的scaleType属性与adjustViewBounds属性
    安卓计算器 简单代码
    安卓单选、复选按钮简单练习
    安卓发送邮箱界面 线形、表格、相对布局方式
    UI和View 三种控制方式
  • 原文地址:https://www.cnblogs.com/phile/p/4533415.html
Copyright © 2020-2023  润新知