「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