题目描述:
给出一个无向图,求图中每个点是多少对点对的必经点。
输入格式:
第一行输入两个正整数n,m,含义同题目描述。接下来m行,每行两个整数a,b表示a,b两个通讯基站能够直接通讯。
输出格式:
输出n行,每行一个整数,第i行表示通讯基站i是多少对不同的通讯基站的必经点。
样例输入:
样例输出:
数据范围:
对于50%的数据n ≤ 5000,m≤10000;对于100%的数据n ≤ 50000,m≤100000。
时间限制:
1S
空间限制:
256M
应该是很经典的题目了 ,,好像lyd在wc里也讲过的。。囧
一看肯定只有割点的答案大于n-1,非割点答案一定是n-1。
然后就找了个割点,然后以每个割点 O(n)做一遍乘一下。。然后就50分了。。
直接暴力还要T。。搞笑啊。。。
标算:
令原图为a,新建一个图为b,
求出a图每一个点双,在a中每一个点双对应b图新建一个点,每个点双上的点向新建点连边。
然后图就变成树了! 然后怎么搞都行了。。
时间不多了,要走了直接放代码好了。。
暴力:
#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
int getx(){
char c;int x;
for (c=getchar();c<'0'||c>'9';c=getchar());
for (x=0;c>='0'&&c<='9';c=getchar())
x=(x<<3)+(x<<1)+c-'0';
return x;
}
bool upmin(int &a,const int &b){return a>b?a=b,1:0;}
const int MAX_N=50005,MAX_M=100005;
int first[MAX_N],next[MAX_M],to[MAX_M],tal=0;
void tjb(int x,int y){
next[++tal]=first[x];
first[x]=tal;to[tal]=y;
}
int dfn[MAX_N],low[MAX_N],Time;
bool cut[MAX_N],vis[MAX_N];
void tar(int v,int fa){
dfn[v]=low[v]=++Time;
vis[v]=true;
int cnt=0;
for (int k=first[v];k;k=next[k]){
int u=to[k];
if (u==fa) continue;
if (!vis[u]) tar(u,v),cnt++;
upmin(low[v],low[u]);
if (!fa&&cnt>1) cut[v]=true;
if (fa&&low[u]>=dfn[v]) cut[v]=true;
}
}
int n,m;
int fa[MAX_N];
int getfa(int v){return fa[v]==v?fa[v]:(fa[v]=getfa(fa[v]));}
void dfs(int v){
vis[v]=true;
for (int k=first[v];k;k=next[k]){
int u=to[k];
if (vis[u]) continue;
fa[getfa(u)]=getfa(v);
dfs(u);
}
}
int size[MAX_N];
bool px[MAX_N];
long long ans=0;
int main(){
freopen("3.in","r",stdin);
freopen("3.out","w",stdout);
n=getx(),m=getx();
rep(i,1,m){
int x=getx(),y=getx();
tjb(x,y),tjb(y,x);
}
tar(1,0);
rep(i,1,n){
if (cut[i]){
ans=0;
rep(j,1,n) size[j]=0,fa[j]=j,px[j]=vis[j]=0;
vis[i]=true;
for (int k=first[i];k;k=next[k])
if (!vis[to[k]]) dfs(to[k]);
rep(j,1,n) size[getfa(j)]++;
int sum=0;
for (int k=first[i];k;k=next[k]){
int tp=getfa(to[k]);
if (!px[tp]){px[tp]=true;sum+=size[tp];}
}
for (int k=first[i];k;k=next[k]){
int tp=getfa(to[k]);
if (px[tp]){
px[tp]=false;
ans+=(long long)(sum-size[tp])*size[tp];
}
}
printf("%lld\n",ans/2+n-1);
}
else printf("%d\n",n-1);
}
}
std:
#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
typedef long long LL;
bool upmin(int &a,const int &b){return a>b?a=b,1:0;}
int getx(){
char c;int x;
for (c=getchar();c<'0'||c>'9';c=getchar());
for (x=0;c>='0'&&c<='9';c=getchar())
x=(x<<3)+(x<<1)+c-'0';
return x;
}
const int MAX_N=50005*2,MAX_M=100000*4;
struct n_i$s_h$i_d_a$s$b${
int first[MAX_N],next[MAX_M],to[MAX_M],tal;
int n;
void tjb(int x,int y){
next[++tal]=first[x];
first[x]=tal;
to[tal]=y;
}
}a,b;
int dfn[MAX_N],low[MAX_N];
int sta[MAX_N],top,Time=0;
bool vis[MAX_N];
void tar(int v,int fa){
dfn[v]=low[v]=++Time;
vis[v]=true;
for (int k=a.first[v];k;k=a.next[k]){
int u=a.to[k];
if (u==fa) continue;
if (!vis[u]){
sta[++top]=k;
tar(u,v);
upmin(low[v],low[u]);
if (low[u]>=dfn[v]){
b.n++;
while (sta[top+1]!=k){
u=sta[top--];
b.tjb(b.n,a.to[u]);
b.tjb(a.to[u],b.n);
}
b.tjb(b.n,v);b.tjb(v,b.n);
}
}else upmin(low[v],low[u]);
}
}
int n,m;
int w[MAX_N];
LL ans[MAX_N];
int dfs(int v,int fa){
int res=0;
for (int k=b.first[v];k;k=b.next[k]){
int u=b.to[k];
if (u==fa) continue;
res+=dfs(u,v);
}
ans[v]+=(n-1-res)*res;
for (int k=b.first[v];k;k=b.next[k]){
int u=b.to[k];
if (u==fa) continue;
ans[v]+=(LL)w[u]*(n-1-w[u]);
}
ans[v]=ans[v]/2+n-1;
return w[v]=res+(v<=n);
}
int main(){
freopen("3.in","r",stdin);
freopen("3x.out","w",stdout);
n=getx(),m=getx();
rep(i,1,m){
int x=getx(),y=getx();
a.tjb(x,y),a.tjb(y,x);
}
b.n=n;
tar(1,0);
dfs(1,0);
rep(i,1,n) printf("%lld\n",ans[i]);
}