[hdu2460]network(依次连边并询问图中割边数量) tarjan边双联通分量+lca

题意:

给定一个n个点m条边的无向图,q个操作,每个操作给(x,y)连边并询问此时图中的割边有多少条。(连上的边会一直存在)

n<=1e5,m<=2*10^5,q<=1e3,多组数据。

 

题解:

用tarjan求边双连通分量并缩点,缩点后组成一棵树,记录此时割边共有sum条。

连接(x,y),设c[i]为缩点后i所在的新点(边双连通分量),则c[x]-->lca-->c[y]形成一个环,环上的所有边都不再是割边,走一遍并标记,如果遇到没标记过的就sum--。

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 using namespace std;
  6 
  7 const int N=100010,M=200010,K=20;
  8 int n,m,al,bl,sum,num,sl,cnt;
  9 int afirst[N],bfirst[N],fa[N][K],dfn[N],low[N],is[N],c[N],s[N],dep[N];
 10 struct node{
 11     int x,y,tmp,next;
 12 }a[2*M],b[2*M];
 13 
 14 int minn(int x,int y){return x<y ? x:y;}
 15 
 16 void ins_a(int x,int y)
 17 {
 18     a[++al].x=x;a[al].y=y;a[al].tmp=0;
 19     a[al].next=afirst[x];afirst[x]=al;
 20 }
 21 
 22 void ins_b(int x,int y)
 23 {
 24     b[++bl].x=x;b[bl].y=y;
 25     b[bl].next=bfirst[x];bfirst[x]=bl;
 26 }
 27 
 28 void tarjan(int x)
 29 {
 30     dfn[x]=low[x]=++num;
 31     s[++sl]=x;
 32     for(int i=afirst[x];i;i=a[i].next)
 33     {
 34         if(a[i].tmp) continue;
 35         a[i].tmp=1;
 36         a[i%2==0 ? i-1:i+1].tmp=1;
 37         int y=a[i].y;
 38         if(!dfn[y])
 39         {
 40             tarjan(y);
 41             low[x]=minn(low[x],low[y]);
 42             if(dfn[x]<low[y])
 43             {
 44                 sum++;//printf("%d -- > %d\n",x,y);
 45                 cnt++;
 46                 int z;
 47                 while(1)
 48                 {
 49                     z=s[sl--];
 50                     c[z]=cnt;
 51                     if(z==y) break;
 52                 }
 53             }
 54         }
 55         else low[x]=minn(low[x],dfn[y]);
 56     }
 57 }
 58 
 59 void dfs(int x)
 60 {
 61     for(int i=bfirst[x];i;i=b[i].next)
 62     {
 63         int y=b[i].y;
 64         if(y==fa[x][0]) continue;
 65         fa[y][0]=x;dep[y]=dep[x]+1;
 66         dfs(y);
 67     }
 68 }
 69 
 70 void prepare_lca()
 71 {
 72     memset(fa,0,sizeof(fa));
 73     memset(dep,0,sizeof(dep));
 74     memset(is,0,sizeof(is));
 75     dep[1]=1;
 76     dfs(1);
 77     for(int j=1;j<=18;j++)
 78         for(int i=1;i<=n;i++)
 79             fa[i][j]=fa[fa[i][j-1]][j-1];
 80 }
 81 
 82 int get_lca(int x,int y)
 83 {
 84     if(dep[x]<dep[y]) swap(x,y);
 85     for(int i=18;i>=0;i--)
 86         if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
 87     if(x==y) return x;
 88     for(int i=18;i>=0;i--)
 89     {
 90         if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
 91     }
 92     return fa[x][0];
 93 }
 94 
 95 void del(int x,int y,int lca)
 96 {
 97     while(x!=lca) 
 98     {
 99         if(!is[x]) sum--;
100         is[x]=1;
101         x=fa[x][0];
102     }
103     while(y!=lca)
104     {
105         if(!is[y]) sum--;
106         is[y]=1;
107         y=fa[y][0];
108     }
109 }
110 
111 int main()
112 {
113     freopen("a.in","r",stdin);
114     int q,x,y,T=0;
115     while(1)
116     {
117         scanf("%d%d",&n,&m);
118         if(!n && !m) return 0;
119         printf("Case %d:\n",++T);
120         al=0;bl=0;sum=0;
121         memset(afirst,0,sizeof(afirst));
122         memset(bfirst,0,sizeof(bfirst));
123         num=0;sl=0;cnt=0;
124         memset(dfn,0,sizeof(dfn));
125         memset(c,0,sizeof(c));
126         for(int i=1;i<=m;i++)
127         {
128             scanf("%d%d",&x,&y);
129             ins_a(x,y);ins_a(y,x);
130         }
131         for(int i=1;i<=n;i++)
132         {
133             if(!dfn[i]) 
134             {
135                 tarjan(i);
136                 if(sl) 
137                 {
138                     cnt++;
139                     for(int i=1;i<=sl;i++) c[s[i]]=cnt;
140                     sl=0;
141                 }
142             }
143         }
144             
145         for(int i=1;i<=2*m;i++)
146         {
147             x=a[i].x,y=a[i].y;
148             if(c[x]!=c[y]) ins_b(c[x],c[y]);
149         }
150         // for(int i=1;i<=bl;i++) 
151             // printf("%d -- > %d\n",b[i].x,b[i].y);
152         // for(int i=1;i<=n;i++) printf("c [ %d ] = %d\n",i,c[i]);
153         prepare_lca();
154         scanf("%d",&q);
155         for(int i=1;i<=q;i++)
156         {
157             scanf("%d%d",&x,&y);
158             x=c[x];y=c[y];
159             int lca=get_lca(x,y);
160             del(x,y,lca);
161             printf("%d\n",sum);
162         }
163         printf("\n");
164     }
165     return 0;
166 }

 

[hdu2460]network(依次连边并询问图中割边数量) tarjan边双联通分量+lca

上一篇:RxJava+RxAndroid+MVP入坑实践(基础篇)


下一篇:三维物体跟随鼠标移动