LOJ10104Blockade

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\n",ans[i]);
59     return 0;    
60 }
View Code

 

posted on 2019-07-19 11:06  gryzy  阅读(182)  评论(0编辑  收藏  举报

导航