BZOJ 1123: [POI2008]BLO 求割点+乘法原理+计数
Description
Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。
Input
输入n<=100000 m<=500000及m条边
Output
输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。
题解:
一段巧妙的代码:
if(low[to[v]]>=pre[u]) { answer[u]+=(ll)t*siz[to[v]]; t+=siz[to[v]]; }
考虑要实现每两个联通块之间分别乘一次,并加和.
用这种方式可以实现每两个联通块之间只乘一次.
Code:
#include<bits/stdc++.h> #define setIO(s)freopen(s".in","r",stdin) #define maxn 1100000 using namespace std; int n; #define ll long long long long answer[maxn]; int cnt=0,scc=0; int nex[maxn],to[maxn],head[maxn]; void add(int u,int v){ nex[++cnt]=head[u],head[u]=cnt,to[cnt]=v;} int low[maxn],pre[maxn]; ll siz[maxn]; void dfs(int u,int fa){ low[u]=pre[u]=++scc; siz[u]=1; ll t=0; for(int v=head[u];v;v=nex[v]){ if(to[v]==fa) continue; if(pre[to[v]]) low[u]=min(low[u],pre[to[v]]); else { dfs(to[v],u); siz[u]+=siz[to[v]]; if(low[to[v]]>=pre[u]) { answer[u]+=(ll)t*siz[to[v]]; t+=siz[to[v]]; } low[u]=min(low[u],low[to[v]]); } } answer[u]+=(ll)((ll)n-t-1)*t; } int main() { //setIO("input"); int m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v),add(v,u); } dfs(1,0); for(int i=1;i<=n;i++) printf("%lld\n",(ll)(answer[i]+(ll)n-1)*2); return 0; }