当前位置: 代码迷 >> 综合 >> bzoj 1123: [POI2008]BLO
  详细解决方案

bzoj 1123: [POI2008]BLO

热度:48   发布时间:2023-10-29 08:57:23.0

题意

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

题解

这题的话,还是很好做的吧。。
在TJ的过程中,假如一点点DP的小元素就可以了
感觉这个算法还是很好理解的吧,你可以理解为随便搞一个生成树,然后再在上面加边搞事情
然后这个的话,考虑一个,割掉它就是让他返祖边不能回到他上方的子树断掉
然后把全部这样的子树拿出来
乘法原理搞一波就可以了

CODE:

#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=500005;
struct qq
{LL x,y,last;
}e[N*2];LL num,last[N];
LL ans[N];
LL n,m;
void init (LL x,LL y)
{num++;e[num].x=x;e[num].y=y;e[num].last=last[x];last[x]=num;
}
LL low[N],dfn[N],id;
LL tot[N];//这个子树有多少人
void dfs (LL x,LL fa)
{tot[x]=1;low[x]=dfn[x]=++id;vector<int> o;LL cnt=0;LL up=0,down=0;for (LL u=last[x];u!=-1;u=e[u].last){LL y=e[u].y;if (y==fa) continue;if (dfn[y]==0){dfs(y,x);tot[x]+=tot[y];low[x]=min(low[x],low[y]);if (low[y]>=dfn[x]) {o.push_back(y);down=down+tot[y];}else up=up+tot[y];}else low[x]=min(low[x],dfn[y]);}up=up+n-tot[x];cnt=o.size();if (cnt==0) return ;if (cnt==1&&x==1) return ;for (int u=0;u<cnt;u++){int y=o[u];ans[x]=ans[x]+tot[y]*up*2;ans[x]=ans[x]+tot[y]*(down-tot[y]);}
}
int main()
{num=0;memset(last,-1,sizeof(last));scanf("%lld%lld",&n,&m);for (LL u=1;u<=m;u++){LL x,y;scanf("%lld%lld",&x,&y);init(x,y);init(y,x);}dfs(1,0);for (LL u=1;u<=n;u++) printf("%lld\n",ans[u]+(n-1)*2);return 0;
}