[POI2008]BLO-Blockade 【无向图tarjan/鸽点】By cellur925
lyd无向图tarjan的例题。
一句话题意(不得不佩服lyd老师的高度概括能力):在一张无向连通图上,求出每个点被破坏(去掉与这个点相关的所有边,不去掉这个点)后,无向图中使i,j不连通有序点对(i,j)个数。
浓浓的鸽点气息。
但是这题又不单单是鸽点。
我们冷静分析,分类讨论(分类讨论这个美好的品质常被oier所忽略)
每个点有两种类型:是鸽点/不是鸽点
一、不是鸽点
那么去掉这个点所连的所有边后,只有这个点和剩下的点不连通,而其他点还联系的好好地,所以答案即为2*(n-1),由于是无序点对,所以乘2.
二、是鸽点
那么图会分裂成几个联通块,答案是这几个联通块的大小两两相乘再相加。
我真懒,真的。
size[i]表示以i为根的子树大小。我们可以在tarjan跑鸽点的时候顺便求出。
大体思路就是这样,还是比较简单易懂的。
Code
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 typedef long long ll; 6 7 int n,m,tot,num; 8 int head[100090],dfn[100090],low[100090]; 9 bool cut[100090]; 10 ll size[100090],ans[100090]; 11 struct node{ 12 int to,next; 13 }edge[1000090]; 14 15 void add(int x,int y) 16 { 17 edge[++tot].to=y; 18 edge[tot].next=head[x]; 19 head[x]=tot; 20 } 21 22 void tarjan(int x) 23 { 24 dfn[x]=low[x]=++num;size[x]=1; 25 int flag=0;ll sigma=0; 26 for(int i=head[x];i;i=edge[i].next) 27 { 28 int y=edge[i].to; 29 if(!dfn[y]) 30 { 31 tarjan(y); 32 size[x]+=size[y]; 33 low[x]=min(low[x],low[y]); 34 if(low[y]>=dfn[x]) 35 { 36 flag++; 37 ans[x]+=1ll*size[y]*(n-size[y]); 38 sigma+=size[y]; 39 if(x!=1||flag>1) cut[x]=true; 40 } 41 } 42 else low[x]=min(low[x],dfn[y]); 43 } 44 if(cut[x])//是鸽点 45 ans[x]+=1ll*(n-sigma-1)*(1+sigma)+(n-1); 46 else //不是鸽点 47 ans[x]=1ll*2*(n-1); 48 } 49 50 int main() 51 { 52 scanf("%d%d",&n,&m); 53 for(int i=1;i<=m;i++) 54 { 55 int x=0,y=0; 56 scanf("%d%d",&x,&y); 57 if(x==y) continue; 58 //去掉自环 59 add(x,y); 60 add(y,x); 61 } 62 tarjan(1); 63 //图保证联通。只调用一次便足够。 64 //意念起点为1 65 for(int i=1;i<=n;i++) 66 printf("%lld\n",ans[i]); 67 return 0; 68 }
独立意志与自由思想是必须争的,且须以生死力争。