【bzoj1123】【[POI2008]BLO】tarjan判割点

来源:互联网 发布:360手机文件夹加密软件 编辑:程序博客网 时间:2024/05/23 19:20

这里写图片描述
(上不了p站我要死了,侵权度娘背锅)

Description
Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。
Input
输入n<=100000 m<=500000及m条边
Output
输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。
Sample Input
5 5
1 2
2 3
1 3
3 4
4 5
Sample Output
8
8
16
14
8

很明显的判割点
写来练练手,熟悉模板
割点的子树和其他部分不连通,除去子树的剩余部分与子树不连通。乘法原理。
注意会爆int

代码

#include<cstdio>#include<cstring>#include<algorithm>#define ll long long using namespace std;inline int read(){    int k=1,x=0;char ch=0;    while(ch<'0'||ch>'9'){if(ch=='-')k=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return x*k;}const int N=100000+5;const int M=500000+5;int n,m;int head[N],end[M*2],nxt[M*2],hh=1;int idc,dfn[N],low[N];ll siz[N],ans[N];bool vis[M*2];void adde(int a,int b){    hh++;    end[hh]=b;    nxt[hh]=head[a];    head[a]=hh;}void tarjan(int u){    idc++;    dfn[u]=low[u]=idc;    siz[u]=1,ans[u]=n-1;    bool bj=0;    ll cnt=0,sizz=1;    for(int i=head[u];i;i=nxt[i]){        if(vis[i]) continue;        cnt++;        vis[i]=vis[i^1]=1;        int v=end[i];        if(dfn[v]){            low[u]=min(low[u],dfn[v]);        }        else{            tarjan(v);            siz[u]+=siz[v];            low[u]=min(low[v],low[u]);            if(low[v]>=dfn[u]){                bj=1;                ans[u]+=siz[v]*(n-siz[v]);                sizz+=siz[v];            }        }    }    if(u==1&&cnt<=1) ans[u]=(n-1)*2;    if(u!=1&&bj==0) ans[u]=(n-1)*2;    if(u!=1&&bj||u==1&&cnt>1) ans[u]+=(n-sizz)*sizz;}int main(){    n=read(),m=read();    for(int i=1;i<=m;i++){        int a,b;        a=read(),b=read();        adde(a,b),adde(b,a);    }    tarjan(1);    for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);    return 0;}