[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 }

原文地址:https://www.cnblogs.com/KonjakJuruo/p/9708552.html

时间: 2024-10-28 23:43:36

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

poj3694 network(边双联通分量+lca+并查集)

题    目    传    送    们    在    这 题目大意 有一个由n个点和m条边组成的无向联通图. 现在有Q个操作,每次操作可以在点x,y之间连一条边. 问你每次操作后有多少个多少个桥(即删掉后就会使图不联通的边). 解题思路 根据边双联通的定义,我们知道将边双联通分量缩点后的图,其中的边即为桥. 我们将这个图缩点,就变成了一棵树. 而每次在两个不同的边双联通分量x,y之间加边后,就出现了一个包含x,y的环,其中原先这颗树上x,y的树上最短路径就不在是边. 所以对于每个x,y,我

边双联通分量(构造边双联通图)

1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 #include <algorithm> 6 #include <cstring> 7 #include <stack> 8 #include <cctype> 9 #include <queue> 10 #include <s

求图中欧拉回路数量

问题描述:输入点数n.边数m.每条边连接的两个点a,b,求此无向图中不包括一个点本身的欧拉回路数量,重复不计: 解决此问题,则需要在深搜的基础上判断新搜出的欧拉回路是否已经被走过,可以利用搜索时所打的标记来判断: 使用邻接表,需要注意在无向图中连接两点有两条边,要同时考虑: 以下为代码: #include<iostream>#include<cstdio>#include<cstring>using namespace std;int n,m,cnt[105],ct,q

POJ 3177 Redundant Paths(边双联通图)

Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forc

[HDU2460]Network

Network 题目大意 给你一个无向连通图,再给出一些添边操作,询问每次添边操作之后图中还剩下多少桥. Solution 其实很水,缩个点,然后此时图是一棵树,其中每条边都是割边,然后每次加边就把左右端点路径上的所有边都变成非割边即可 树剖维护一下.放这个题的原因就是码量大了一点. upd:有一个码量很小的生成树的做法...我哭了 code: #include<bits/stdc++.h> using namespace std; struct qwq{ int v; int nxt; }e

java 数据结构 图中使用的一些常用算法 图的存储结构 邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 实例如下,左图是一个无向图。右图是邻接矩阵表示:

以下内容主要来自大话数据结构之中,部分内容参考互联网中其他前辈的博客. 图的定义 图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图,V是图G中顶点的集合,E是图G中边的集合. 无边图:若顶点Vi到Vj之间的边没有方向,则称这条边为无项边(Edge),用序偶对(Vi,Vj)标示. 对于下图无向图G1来说,G1=(V1, {E1}),其中顶点集合V1={A,B,C,D}:边集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)}: 有向图:若

矩阵图中的广度优先搜索

经常会有类似的题目,如迷宫问题,在一个矩阵图中给定出发点和目标点,每次只能上下左右移动,求到目标点的最短走法,或者说是一共有多少种走法. 思路其实很简单,深搜.广搜.相对比较而言,广度优先搜索更加实用于求最短的走法(步数) 在矩阵图中的广搜需要注意一下几点. 1.确定每步的走法:不同题的走法可能不同,每次搜索时将走法保存在数组中. 2.确定初始状态 往往注意刚开始得起点(i,j)必须把MAP(i,j)改变为 -1(或者其他的),栈中第一个元素即为初始状态 3.保存状态.这点很重要.需要用数组或者

poj 2117 Electricity 【无向图求割点】【求去掉一个点后 图中最多的BCC数目】

Electricity Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4597   Accepted: 1515 Description Blackouts and Dark Nights (also known as ACM++) is a company that provides electricity. The company owns several power plants, each of them sup

UML类图中的六大关系:泛化、实现、依赖、关联、聚合、组合关系

UML定义的关系主要有:泛化.实现.依赖.关联.聚合.组合,这六种关系紧密程度依次加强,分别看一下 1.泛化 概念:泛化是一种一般与特殊.一般与具体之间关系的描述,具体描述建立在一般描述的基础之上,并对其进行了扩展.在程序中是通过继承类实现的.比如狗是对动物的具体描述,在面向对象设计的时候一般把狗设计为动物的子类. 表示方法:空心三角形箭头的实线,子类指向父类 2.实现 概念:实现是一种类与接口的关系,表示类是接口所有特征和行为的实现,在程序中一般通过类实现接口来描述 表示方法:空心三角形箭头的