[POI2008]BLO
[POI2008]BLO-Blockade
题意翻译
在Byteotia有n个城镇。 一些城镇之间由无向边连接。 在城镇外没有十字路口,尽管可能有桥,隧道或者高架公路(反正不考虑这些)。每两个城镇之间至多只有一条直接连接的道路。人们可以从任意一个城镇直接或间接到达另一个城镇。 每个城镇都有一个公民,他们被孤独所困扰。事实证明,每个公民都想拜访其他所有公民一次(在主人所在的城镇)。所以,一共会有n*(n-1)次拜访。
不幸的是,一个程序员总罢工正在进行中,那些程序员迫切要求购买某个软件。
作为抗议行动,程序员们计划封锁一些城镇,阻止人们进入,离开或者路过那里。
正如我们所说,他们正在讨论选择哪些城镇会导致最严重的后果。
编写一个程序:
读入Byteotia的道路系统,对于每个被决定的城镇,如果它被封锁,有多少访问不会发生,输出结果。
输入输出格式
第一行读入n,m,分别是城镇数目和道路数目
城镇编号1~n
接下来m行每行两个数字a,b,表示a和b之间有有一条无向边
输出n行,每行一个数字,为第i个城镇被锁时不能发生的访问的数量。
翻译提供者:Park
给定一张无向图,求每个点被封锁之后有多少个有序点对(x,y)(x!=y,1<=x,y<=n)满足x无法到达y
输入样例#1: 复制5 5 1 2 2 3 1 3 3 4 4 5
8 8 16 14 8
cy41的题解
还有人把书拍了照发到网上的,佩服。
考虑删除的点为割点和非割点:设总共有n个点,第i个点断开;
- 非割点,不会改变其余n-1个点的连通性,那么剩下的n-1个点都是连通的,故只有i点与别的点都不连通,那么此时的有序点对为:2*(n-1);
- 割点,那么去掉这些与i点相连的边后,会划分成若干个连通块,若我们已知每个连通块内的点数,那么将他们两两相乘再相加即为有序点对;
好的,这时问题转化为了如何快速的求出去掉i点后,各个连通块内的点个数。
我们其实可以将连通块的种类分为3种,其一是i点自身,二是除了i点的与之有直连边的割点构成的连通块,三是除去i,与之有直连边的割点以外,剩下的所有点构成的块。

其中SIZE[S1]*(n-SIZE[S1])表示该连通块到其他别的点都是不连通的,1*(n-1)为那个去掉的第i个点到其他点不连通,
最后那个()*()就是除了割点,除了被去掉的这个点构成的点的集合,到割点及i点的不连通。
时间复杂度\(O(n)\)
co int N=1e5+1,M=5e5+1;
int head[N],ver[M*2],next[M*2];
int dfn[N],low[N],siz[N];
ll ans[N];
bool cut[N];
int n,m,tot,num;
il void add(int x,int y){
ver[++tot]=y,next[tot]=head[x],head[x]=tot;
}
void tarjan(int x){
dfn[x]=low[x]=++num,siz[x]=1;
int flag=0,sum=0;
for(int i=head[x],y;i;i=next[i]){
if(!dfn[y=ver[i]]){
tarjan(y);
low[x]=std::min(low[x],low[y]),siz[x]+=siz[y];
if(low[y]>=dfn[x]){
++flag;
ans[x]+=(ll)siz[y]*(n-siz[y]);
sum+=siz[y];
if(x!=1||flag>1) cut[x]=1;
}
}
else low[x]=std::min(low[x],dfn[y]);
}
if(cut[x]) ans[x]+=(ll)(n-sum-1)*(sum+1)+(n-1);
else ans[x]=2*(n-1);
}
int main(){
read(n),read(m);
for(int i=1,x,y;i<=m;++i){
read(x),read(y);
if(x==y) continue;
add(x,y),add(y,x);
}
tarjan(1);
for(int i=1;i<=n;++i) printf("%lld\n",ans[i]);
return 0;
}
浙公网安备 33010602011771号