zoukankan      html  css  js  c++  java
  • 动态图连通性问题(离线/在线)

    有这样一类问题(例:loj121,122),要求在无向图中实现如下操作:

    1.增加一条边

    2.删除一条边

    3.询问两点是否连通

    这类问题有离线做法和在线做法,两者的思想完全不同

    离线做法的思想是,考虑到每一条边存在的时间范围是一个区间,在线段树对应的区间打上标记,然后从根节点自顶向下dfs,每访问一个区间,把该区间上打过标记的所有边都加进去,回溯时再删除,用带撤销并查集维护连通性即可,访问到叶子结点的时候输出答案

    复杂度$O(mlogmlogn)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=5e5+10,inf=0x3f3f3f3f;
     5 int n,m,fa[N],siz[N],sta[N],tp,sum[N<<2];
     6 struct QR {int f,u,v;} a[N];
     7 struct E {
     8     int u,v;
     9     bool operator<(const E& b)const {return u!=b.u?u<b.u:v<b.v;}
    10 };
    11 vector<E> vec[N<<2];
    12 map<E,int> mp;
    13 #define l(u) (u<<1)
    14 #define r(u) (u<<1|1)
    15 #define mid ((l+r)>>1)
    16 void pu(int u) {sum[u]=sum[l(u)]+sum[r(u)];}
    17 void build(int u=1,int l=1,int r=m) {
    18     if(l==r) {sum[u]=(a[l].f==2); return;}
    19     build(l(u),l,mid),build(r(u),mid+1,r),pu(u);
    20 }
    21 void upd(int L,int R,E x,int u=1,int l=1,int r=m) {
    22     if(l>=L&&r<=R) {vec[u].push_back(x); return;}
    23     if(l>R||r<L)return;
    24     upd(L,R,x,l(u),l,mid),upd(L,R,x,r(u),mid+1,r);
    25 }
    26 int fd(int x) {return fa[x]?fd(fa[x]):x;}
    27 void mg(int x,int y) {
    28     if((x=fd(x))==(y=fd(y)))return;
    29     if(siz[x]>siz[y])swap(x,y);
    30     fa[x]=y,siz[y]+=siz[x];
    31     sta[++tp]=x;
    32 }
    33 void sp(int x) {siz[fa[x]]-=siz[x],fa[x]=0;}
    34 void dfs(int u=1,int l=1,int r=m) {
    35     if(!sum[u])return;
    36     int now=tp;
    37     for(E x:vec[u])mg(x.u,x.v);
    38     if(l==r) {
    39         puts(fd(a[l].u)==fd(a[l].v)?"Y":"N");
    40         for(; tp>now; --tp)sp(sta[tp]);
    41         return;
    42     }
    43     dfs(l(u),l,mid),dfs(r(u),mid+1,r);
    44     for(; tp>now; --tp)sp(sta[tp]);
    45 }
    46 
    47 int main() {
    48     scanf("%d%d",&n,&m);
    49     for(int i=1; i<=n; ++i)fa[i]=0,siz[i]=1;
    50     for(int i=1; i<=m; ++i) {
    51         scanf("%d%d%d",&a[i].f,&a[i].u,&a[i].v);
    52         if(a[i].u>a[i].v)swap(a[i].u,a[i].v);
    53     }
    54     for(int i=1; i<=m; ++i) {
    55         E x= {a[i].u,a[i].v};
    56         if(a[i].f==0)mp[x]=i;
    57         else if(a[i].f==1) {
    58             int l=mp[x],r=i-1;
    59             upd(l,r,x);
    60             mp.erase(x);
    61         }
    62     }
    63     for(auto t:mp) {
    64         E x=t.first;
    65         int l=t.second,r=m;
    66         upd(l,r,x);
    67     }
    68     mp.clear();
    69     build();
    70     dfs();
    71     return 0;
    72 }
    View Code

    在线做法有一个叫做Holm-de Lichtenberg-Thorup的算法,比较复杂,其基本思想是动态维护生成树,如果生成树上的边被删除了,那么就需要寻找可以替代的边。

    寻找替代边的过程可以表示为:假设生成树上的某条边被删除,使得原生成树被分割成两棵子树F,F',假设siz[F]<siz[F'],那么就从F的结点中连出的边里寻找连向F'的(显然,每一条边的两个端点,要么全在F中,要么一个在F中一个在F'中)。为了加速这个过程,需要给每条边赋予一个优先级,每次寻找重连边时优先级高的首先考虑。初始优先级为0,如果在F中寻找到某条边不能够连向F',那么就把这条边的优先级+1,由于每条边优先级+1必然伴随着结点数量减半,因此每条边最多被考虑O(logn)次。可以用带子树查询的LCT维护各种信息

    复杂度$O(mlog^2n)$,常数巨大

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 const int N=5e3+10,M=1e9+7;
      5 int n,m;
      6 #define l(u) ch[u][0]
      7 #define r(u) ch[u][1]
      8 struct HDLT {
      9     static const int N=5e3+10;
     10     int blocks;
     11     ll f(int x,int y) {return (ll)x*M+y;}
     12     struct LCT {
     13         struct List {
     14             int hd[N],pre[N],nxt[N];
     15             void init(int n) {for(int u=1; u<=n; ++u)hd[u]=0;}
     16             void link(int u,int v) {
     17                 if(!hd[u])hd[u]=pre[v]=nxt[v]=v;
     18                 else {
     19                     int x=hd[u],y=pre[x];
     20                     pre[x]=nxt[y]=v;
     21                     pre[v]=y,nxt[v]=x;
     22                 }
     23             }
     24             void cut(int u,int v) {
     25                 if(nxt[v]==v)hd[u]=0;
     26                 else {
     27                     if(hd[u]==v)hd[u]=nxt[v];
     28                     pre[nxt[v]]=pre[v],nxt[pre[v]]=nxt[v];
     29                 }
     30             }
     31             bool empty(int u) {return hd[u]==0;}
     32             int first(int u) {return hd[u];}
     33         } chv[2];
     34         unordered_set<int> G[N][2];
     35         void linkv(int u,int v) {
     36             if(!u||!v)return;
     37             sizv[u]+=siz[v];
     38             for(int i=0; i<2; ++i)if(tag[v][i])chv[i].link(u,v);
     39         }
     40         void cutv(int u,int v) {
     41             if(!u||!v)return;
     42             sizv[u]-=siz[v];
     43             for(int i=0; i<2; ++i)if(tag[v][i])chv[i].cut(u,v);
     44         }
     45         int fa[N],ch[N][2],flp[N],sta[N],tp,siz[N],sizv[N],tag[N][2];
     46         void rev(int u) {flp[u]^=1,swap(l(u),r(u));}
     47         void pu(int u) {
     48             if(!u)return;
     49             for(int i=0; i<2; ++i)tag[u][i]=tag[l(u)][i]|tag[r(u)][i]|!G[u][i].empty()|!chv[i].empty(u);
     50             siz[u]=siz[l(u)]+siz[r(u)]+1+sizv[u];
     51         }
     52         void pd(int u) {if(flp[u])rev(l(u)),rev(r(u)),flp[u]=0;}
     53         int sf(int u) {return u==r(fa[u]);}
     54         bool isrt(int u) {return u!=l(fa[u])&&u!=r(fa[u]);}
     55         void rot(int u) {
     56             int v=fa[u],f=sf(u);
     57             bool flag=isrt(v);
     58             if(!flag)ch[fa[v]][sf(v)]=u;
     59             else if(fa[v])cutv(fa[v],v);
     60             ch[v][f]=ch[u][f^1],fa[ch[v][f]]=v;
     61             fa[u]=fa[v],ch[u][f^1]=v,fa[v]=u,pu(v);
     62             if(flag)pu(u),linkv(fa[u],u);
     63         }
     64         void splay(int u) {
     65             sta[tp=0]=u;
     66             for(int v=u; !isrt(v); v=fa[v])sta[++tp]=fa[v];
     67             for(; ~tp; pd(sta[tp--]));
     68             for(; !isrt(u); rot(u))if(!isrt(fa[u])&&sf(fa[u])==sf(u))rot(fa[u]);
     69         }
     70         void access(int u) {
     71             int w=u;
     72             for(int v=0; u; u=fa[v=u])splay(u),linkv(u,r(u)),cutv(u,v),r(u)=v,pu(u);
     73             splay(w);
     74         }
     75         void makert(int u) {access(u),rev(u);}
     76         void join(int u,int v) {makert(u),access(v);}
     77         int findrt(int u) {access(u); for(; l(u); pd(u),u=l(u)); splay(u); return u;}
     78         void link(int u,int v) {
     79             makert(u);
     80             if(findrt(v)==u)return;
     81             fa[u]=v,linkv(v,u),pu(v),access(v);
     82         }
     83         void cut(int u,int v) {join(u,v); if(l(v)!=u||r(u))return; fa[u]=l(v)=0,pu(v);}
     84         int get(int u,int f) {
     85             access(u);
     86             if(!tag[u][f])return 0;
     87             while(G[u][f].empty()) {
     88                 if(tag[l(u)][f])u=l(u);
     89                 else if(tag[r(u)][f])u=r(u);
     90                 else u=chv[f].first(u);
     91             }
     92             return u;
     93         }
     94         bool isconnected(int u,int v) {return findrt(u)==findrt(v);}
     95         void ins(int f,int u,int v) {
     96             if(G[u][f].size()==0)access(u);
     97             G[u][f].insert(v),pu(u);
     98             if(G[v][f].size()==0)access(v);
     99             G[v][f].insert(u),pu(v);
    100         }
    101         void del(int f,int u,int v) {
    102             if(G[u][f].size()==1)access(u);
    103             G[u][f].erase(v),pu(u);
    104             if(G[v][f].size()==1)access(v);
    105             G[v][f].erase(u),pu(v);
    106         }
    107         void init(int n) {
    108             for(int i=0; i<2; ++i) {
    109                 chv[i].init(n);
    110                 for(int u=1; u<=n; ++u)G[u][i].clear();
    111             }
    112             for(int u=1; u<=n; ++u)fa[u]=l(u)=r(u)=tag[u][0]=tag[u][1]=flp[u]=sizv[u]=0,siz[u]=1;
    113         }
    114     } F[20];
    115     unordered_map<ll,int> LV;
    116     void instree(int lv,int u,int v) {LV[f(u,v)]=LV[f(v,u)]=lv; F[lv].ins(0,u,v);}
    117     void insgraph(int lv,int u,int v) {LV[f(u,v)]=LV[f(v,u)]=lv; F[lv].ins(1,u,v);}
    118     void deltree(int lv,int u,int v) {F[lv].del(0,u,v);}
    119     void delgraph(int lv,int u,int v) {F[lv].del(1,u,v);}
    120     bool findreplace(int lv,int u,int v) {
    121         F[lv].access(u),F[lv].access(v);
    122         if(F[lv].siz[u]>F[lv].siz[v])swap(u,v);
    123         int t=u,replacev=0;
    124         while((u=F[lv].get(u,0))) {
    125             unordered_set<int>& G=F[lv].G[u][0];
    126             while(G.size()) {
    127                 int v=*G.begin();
    128                 deltree(lv,u,v),instree(lv+1,u,v),F[lv+1].link(u,v);
    129             }
    130         }
    131         u=t;
    132         while((u=F[lv].get(u,1))) {
    133             unordered_set<int>& G=F[lv].G[u][1];
    134             while(G.size()) {
    135                 int v=*G.begin();
    136                 if(F[lv].isconnected(u,v))delgraph(lv,u,v),insgraph(lv+1,u,v);
    137                 else {
    138                     replacev=v,delgraph(lv,u,replacev),instree(lv,u,replacev);
    139                     for(int i=0; i<=lv; ++i)F[i].link(u,replacev);
    140                     break;
    141                 }
    142             }
    143             if(replacev)return 1;
    144         }
    145         return 0;
    146     }
    147     int isconnected(int u,int v) {return F[0].isconnected(u,v);}
    148     int getblocksize(int u) {F[0].access(u); return F[0].siz[u];}
    149     void link(int u,int v) {
    150         if(!isconnected(u,v))F[0].link(u,v),instree(0,u,v),--blocks;
    151         else insgraph(0,u,v);
    152     }
    153     void cut(int u,int v) {
    154         int lv=LV[f(u,v)];
    155         if(F[lv].G[u][0].count(v)) {
    156             for(int i=0; i<=lv; ++i)F[i].cut(u,v);
    157             deltree(lv,u,v);
    158             ++blocks;
    159             for(int i=lv; i>=0; --i)if(findreplace(i,u,v)) {--blocks; break;}
    160         } else delgraph(lv,u,v);
    161     }
    162     void del(int u) {
    163         vector<int> vec;
    164         for(int t=0; t<2; ++t)
    165             for(int i=0; i<20; ++i)
    166                 for(int v:F[i].G[u][t])
    167                     vec.push_back(v);
    168         for(int v:vec)cut(u,v);
    169         --blocks;
    170     }
    171     void init(int n) {
    172         for(int i=0; i<20; ++i)F[i].init(n);
    173         LV.clear(),blocks=n;
    174     }
    175 } solver;
    176 int main() {
    177     scanf("%d%d",&n,&m);
    178     solver.init(n);
    179     for(int lastans=0; m--;) {
    180         int f,u,v;
    181         scanf("%d%d%d",&f,&u,&v);
    182         u^=lastans,v^=lastans;
    183         if(f==0)solver.link(u,v);
    184         else if(f==1)solver.cut(u,v);
    185         else if(f==2) {
    186             int t=solver.isconnected(u,v);
    187             printf("%c
    ",t?'Y':'N');
    188             lastans=(t?u:v);
    189         }
    190     }
    191     return 0;
    192 }
    View Code
  • 相关阅读:
    为什么在SqlServer流水模式下,事务无法启动?
    默认web站点被删除,如何设置新的默认站点?
    用C#实现基于TCP协议的网络通讯
    如何通过DataRelation关联两个DataGrid,实现主从表。
    如何设置网站的会话时间?
    性能测试基本概念释疑
    C#中如何获取服务器IP,名称,操作系统,客户端IP,名称!
    DataGridComboBoxColumn控件
    端口基础知识
    P2P之UDP穿透NAT的原理与实现
  • 原文地址:https://www.cnblogs.com/asdfsag/p/14616690.html
Copyright © 2011-2022 走看看