其他分享
首页 > 其他分享> > 「BZOJ1123」BLO 题解报告

「BZOJ1123」BLO 题解报告

作者:互联网

题目描述

B城有n个城镇。m条双向道路。每条道路连接两个不同的城镇,没有重复的道路,所有城镇连通。

你需要输出n个数,第i个数表示删除结点i关联的边,不删去i结点,有多少个有序对(x,y),满足城镇x和城镇y不连通。

输入

输入n,m及m条边。n<=100000,m<=500000

输出

输出n个数,第i个数表示删除结点i关联的边,不删去i结点,有多少个有序对(x,y),满足城镇x和城镇y不连通。

样例

样例输入1

5 5
1 2
2 3
1 3
3 4
4 5

样例输出1

8
8
16
14
8

代码实现(带注释)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+2,M=5e5+2;
int hd[N],to[N<<1],nxt[N<<1];//图 
int dfn[N],low[N],sz[N];
//dfn:时间戳
//low[i]:在[i的子树中以及通过一条不为树上的边能到达子树的点]的时间戳的最小值 
//sz[i]:以i为根的子树大小 
ll ans[N];
//答案数组 
bool cut[N];
int tot,num,n,m,x,y;
void add(int x,int y){
	to[++tot]=y;
	nxt[tot]=hd[x];
	hd[x]=tot;
}//邻接表 
void tarjan(int x){
	dfn[x]=low[x]=++num;//初始化:时间戳1 
	sz[x]=1;//初始化子树大小 
	int fg=0,sum=0;
	//fg 
	for(int i=hd[x];i;i=nxt[i]){
		int y=to[i];
		if(!dfn[y]){//在树上x是y的baba 
			tarjan(y);
			sz[x]+=sz[y];//维护子树大小数组 
			low[x]=min(low[x],low[y]);
			//y这棵子树都能到 
			if(low[y]>=dfn[x]){//x是割点 
				fg++;
				ans[x]+=(ll)sz[y]*(n-sz[y]);
				sum+=sz[y];
				if(x!=1||fg>1) cut[x]=1;//不为根节点 或 为根节点并且有多个子树 
			}
		}else low[x]=min(low[x],dfn[y]);//x,y不是树上的边 
		//只能到y这一个点		
	}
	if(cut[x]) ans[x]+=(ll)(n-1-sum)*(1+sum)+(n-1); //case 2:yes,you got it 
	else ans[x]=2*(n-1);//case 1:不是割点 
}
int main(){
	cin>>n>>m;
	while(m--){
		cin>>x>>y;
		if(x==y) continue;
		add(x,y),add(y,x);
	}
	tarjan(1);
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<"\n";
	}
	return 0;
}

标签:sz,结点,int,题解,ll,城镇,BLO,ans,BZOJ1123
来源: https://www.cnblogs.com/Aurora1217/p/16379899.html