P3469 [POI2008]BLO-Blockade
Posted suxxsfe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3469 [POI2008]BLO-Blockade相关的知识,希望对你有一定的参考价值。
tarjan 割点
P3469 [POI2008]BLO-Blockade
问题描述
B 城有 (n) 个城镇,(m) 条双向道路。
每条道路连结两个不同的城镇,没有重复的道路,所有城镇连通。
把城镇看作节点,把道路看作边,容易发现,整个城市构成了一个无向图。
输入格式
第一行包含两个整数 (n) 和 (m)。
接下来 (m) 行,每行包含两个整数 (a) 和 (b),表示城镇 (a) 和 (b) 之间存在一条道路。
输出格式
输出共 (n) 行,每行输出一个整数。
第 (i) 行输出的整数表示把与节点 (i) 关联的所有边去掉以后(不去掉节点 (i) 本身),无向图有多少个有序点 ((x,y)),满足 (x) 和 (y) 不连通。
数据范围
(nle 100000),(mle500000)
先用 tarjan 求出割点,对于非割点,除它以外的点的连通性不受他的影响,所以只有它与其它点会不连通,答案是 (2(n-1))
对于那些是割点的点,它会把整个图分成若干个联通块(假设是 (k) 个),那么不连通的点对数就是
就是说每个联通块的点数((a_i)),都与其它点,除去当前这个割点((n-a_i-1)),不相连通
当然这些联通块都是不包含当前这个割点的
那么如何求这些联通块?
tarjan 的时候,对于有向边 ((u,v)),(low_vge dfn_u) 就说明如果不经过 (u),(v) 和它后面的点就不能回到 (u) 之前,那么搜索树中以 (v) 为根的子树,正是一个这样的联通快
假设这个搜索树子树的大小是 (size_v),那么这个 (size_v) 就是 (a_i),直接加到答案里就行了
设 (sum_{(u,v)}size_v=sum),则还应该有一个大小为 (n-sum-1) 的联通块,就是在搜索树中从 (u)“往上”有一个联通块,那么答案还要再加 ((n-sum-1)cdot (n-(n-sum-1)-1)=sum(n-sum-1))
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<‘0‘||c>‘9‘){if(c==‘-‘) y=0;c=std::getchar();}
while(c>=‘0‘&&c<=‘9‘){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
//tarjan 割点
#define N 100006
#define M 1000006
int n,m;
int fir[N],nex[M],to[M],tot;
int cut[N],dfn[N],low[N],dfscnt;
LL ans[N];
inline void add(int x,int y){
to[++tot]=y;
nex[tot]=fir[x];fir[x]=tot;
}
int tarjan(int u,int fa){//return size of subtree u
dfn[u]=low[u]=++dfscnt;
int children=0,size=1,size_v,sum=0;
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(!dfn[v]){
size_v=tarjan(v,fa);
size+=size_v;
low[u]=std::min(low[u],low[v]);
if(low[v]>=dfn[u]){
sum+=size_v;ans[u]+=(LL)size_v*(n-size_v-1);
if(u!=fa) cut[u]=1;
}
children++;
}
else low[u]=std::min(low[u],dfn[v]);
}
ans[u]+=(LL)sum*(n-sum-1);
if(children>1&&u==fa) cut[u]=1;
// std::printf("u : %d size : %d ans : %d
",u,size,ans[u]);
return size;
}
int main(){
n=read();m=read();
for(reg int u,v,i=1;i<=m;i++){
u=read();v=read();
add(u,v);add(v,u);
}
tarjan(1,1);
for(reg int i=1;i<=n;i++)
std::printf("%lld
",(n-1)*2+cut[i]*ans[i]);
//
// EN;EN;
// for(reg int i=1;i<=n;i++) std::printf("dfn : %d low : %d size : %d
",dfn[i],low[i],size[i]);
return 0;
}
以上是关于P3469 [POI2008]BLO-Blockade的主要内容,如果未能解决你的问题,请参考以下文章
luogu P3469 [POI2008]BLO-Blockade 割点
P3469 [POI2008]BLO-Blockade 割点 tarjan