标签:数据 节点 else 影响 register sub 联通 pre tchar
tarjan 割点
P3469 [POI2008]BLO-Blockade
B 城有 \(n\) 个城镇,\(m\) 条双向道路。
每条道路连结两个不同的城镇,没有重复的道路,所有城镇连通。
把城镇看作节点,把道路看作边,容易发现,整个城市构成了一个无向图。
第一行包含两个整数 \(n\) 和 \(m\)。
接下来 \(m\) 行,每行包含两个整数 \(a\) 和 \(b\),表示城镇 \(a\) 和 \(b\) 之间存在一条道路。
输出共 \(n\) 行,每行输出一个整数。
第 \(i\) 行输出的整数表示把与节点 \(i\) 关联的所有边去掉以后(不去掉节点 \(i\) 本身),无向图有多少个有序点 \((x,y)\),满足 \(x\) 和 \(y\) 不连通。
\(n\le 100000\),\(m\le500000\)
先用 tarjan 求出割点,对于非割点,除它以外的点的连通性不受他的影响,所以只有它与其它点会不连通,答案是 \(2(n-1)\)
对于那些是割点的点,它会把整个图分成若干个联通块(假设是 \(k\) 个),那么不连通的点对数就是
就是说每个联通块的点数(\(a_i\)),都与其它点,除去当前这个割点(\(n-a_i-1\)),不相连通
当然这些联通块都是不包含当前这个割点的
那么如何求这些联通块?
tarjan 的时候,对于有向边 \((u,v)\),\(low_v\ge 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\n",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",(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\n",dfn[i],low[i],size[i]);
return 0;
}
标签:数据 节点 else 影响 register sub 联通 pre tchar
原文地址:https://www.cnblogs.com/suxxsfe/p/12742176.html