bzoj1123 求割点+乘法原理

来源:互联网 发布:守望先锋mac能玩吗 编辑:程序博客网 时间:2024/06/14 20:23

题目戳这里:http://www.lydsy.com/JudgeOnline/problem.php?id=1123
1123: [POI2008]BLO
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
题目大意就是去掉每个点,询问不连通的点对有多少组。这道题我们在求割点的基础上,存一下每个连通块的大小,然后乘法原理计算一下就好了,注意要算上这个点本身会与n-1个点不连通,并且答案要乘2因为点对(a,b)和点对(b,a)算两个,答案long long保存。
代码:

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#define N 100005#define M 500005#define dnt long long#define del(a,b) memset(a,b,sizeof(a))using namespace std;int n,m,num,head[N],a,b;struct Edge{    int v,next;};Edge e[10*M];void adde(int i,int j){    e[++num].v=j;    e[num].next=head[i];    head[i]=num;}int siz[N],dfn[N],low[N],idc;dnt ans[N];void tarjan(int u,int fa){    siz[u]=1;    dfn[u]=low[u]=++idc;    dnt rt=0,cnt=0;    for(int i=head[u];i;i=e[i].next){        int v=e[i].v;        if(v==fa)continue;        if(!dfn[v]){            tarjan(v,u);            siz[u]+=siz[v];            low[u]=min(low[u],low[v]);            if(low[v]>=dfn[u]){                cnt+=(dnt)(siz[v])*rt;                rt+=(dnt)(siz[v]);            }        }else low[u]=min(low[u],dfn[v]);    }    cnt+=(n-1-rt)*rt;    ans[u]=cnt;}int main(){    memset(ans,0,sizeof(ans));    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        scanf("%d%d",&a,&b);        adde(a,b);        adde(b,a);    }    tarjan(1,-1);    for(int i=1;i<=n;i++)    printf("%lld\n",(ans[i]+n-1)*2);    return 0;}