POI 2008
Byteotia 城市有 n 个城镇,m 条双向道路。每条道路连接两个不同的城镇,没有重复的道路,所有城镇连通。
输出 n 个数,代表如果把第i 个点去掉,将有多少对点不能互通。
输入格式
输入 n,m 及 m 条边。
输出格式
输出 n 个数,代表如果把第 i 个点去掉,将有多少对点不能互通。
样例
样例输入
5 5
1 2
2 3
1 3
3 4
4 5
样例输出
8
8
16
14
8
数据范围与提示
n<=1e5,m<=5e5。
______________________________________________________
tarjan算法,去掉某一点后产生的点对主要有三种:
1、u点和其他的点
2、u点下的各个子树内的点与其他的点(不含u)
3、u点下的所有子树外的点(可以理解为父亲方向上的子树,但包含于u点同双联通的点)到其他的点
______________________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int maxm=5e5+10; 5 int n,m; 6 struct edge 7 { 8 int u,v,nxt; 9 bool ok; 10 }e[maxm<<1]; 11 int head[maxn],js; 12 void addage(int u,int v) 13 { 14 e[++js].u=u;e[js].v=v; 15 e[js].nxt=head[u];head[u]=js; 16 } 17 int dfn[maxn],low[maxn],cnt,sz[maxn],ch[maxn]; 18 long long ans[maxn]; 19 int fx(int x) 20 { 21 return x&1?x+1:x-1; 22 } 23 void tarjan(int u) 24 { 25 dfn[u]=low[u]=++cnt; 26 sz[u]=1; 27 ans[u]=(n-1)<<1; //当前点与其他点之间的点对 28 for(int i=head[u];i;i=e[i].nxt) 29 if(!e[i].ok) 30 { 31 int v=e[i].v; 32 e[fx(i)].ok=1; 33 if(!dfn[v]) 34 { 35 tarjan(v); 36 sz[u]+=sz[v]; 37 low[u]=min(low[u],low[v]); 38 if(low[v]>=dfn[u]) 39 { 40 ans[u]+=(long long)sz[v]*(n-sz[v]-1); //当前v节点为根的子树到树上其他点的点对(不包含u点) 41 ch[u]+=sz[v]; 42 } 43 } 44 else low[u]=min(low[u],dfn[v]); 45 } 46 ans[u]+=(long long)(n-ch[u]-1)*ch[u]; //树去掉u为根的子树而产生的子树(不包含与u同双联通分量的点)中的点到到树中其他的点得点对 47 } 48 int main() 49 { 50 scanf("%d%d",&n,&m); 51 for(int u,v,i=0;i<m;++i) 52 { 53 scanf("%d%d",&u,&v); 54 addage(u,v); 55 addage(v,u); 56 } 57 tarjan(1); 58 for(int i=1;i<=n;++i)printf("%lld ",ans[i]); 59 return 0; 60 }