题意:
给一个连通无向图,问删掉i号点后有多少点对不相连。
题解:
双连通分量的例题。
首先至少有2*(n-1)(删掉的点也算入点对)
非割点就是这样
考虑割点
因为点双缩点后一定是一棵树,所以可以在树上计数。
我是这么做的,分别计算下所有点双中的点数的和,割点的度数和,还有割点的个数,那么就可以得出一个子树不同的点的个数(可能此方法很sb)
然后就可以计数了。
update:实际上就是最傻逼的打法
其实直接在tarjan的时候乘就可以了,建议看hzwer的。
code:
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
struct node{
int y,next;
}A[1000010],a[400010];int Len=0,Last[100010],len=0,last[200010];
vector<int> V[1000010];
int low[100010],dfn[100010],sta[100010],id=0,tp=0,cnt,num[200010],bel[100010];
LL ans[100010];
bool v[100010],g[100010];
struct trnode{
int g,cnt,num;
}tr[200010];
void insert(int x,int y)
{
A[++Len].y=y;
A[Len].next=Last[x];Last[x]=Len;
}
void ins(int x,int y)
{
a[++len].y=y;
a[len].next=last[x];last[x]=len;
}
int n,m;
void dfs(int x)
{
dfn[x]=low[x]=++id;
sta[++tp]=x;v[x]=true;
int tot=0;
for(int i=Last[x];i;i=A[i].next)
{
int y=A[i].y;
if(dfn[y]==-1)
{
dfs(y);tot++;
low[x]=min(low[x],low[y]);
if(low[y]==dfn[x])
{
g[x]=true;bel[x]=++cnt;
V[x].push_back(cnt);
num[cnt]=1;
while(sta[tp+1]!=y)
{
int z=sta[tp];
if(g[z]) V[z].push_back(cnt);
bel[z]=cnt;v[z]=false;tp--;
num[cnt]++;
}
}
}
else if(v[y]) low[x]=min(low[x],dfn[y]);
}
if(x==1&&tot==1) g[x]=false;
}
int getsum(int x) {return tr[x].num-tr[x].cnt+tr[x].g;}
void solve(int x,int fa)
{
if(x<=n) tr[x].g++;
else tr[x].num=num[x];
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
solve(y,x);
tr[x].g+=tr[y].g;tr[x].num+=tr[y].num;
tr[x].cnt+=tr[y].cnt;tr[x].cnt++;
}
int son=getsum(x);
if(x<=n)
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
int sum=getsum(y);
ans[x]+=(LL)(sum-1)*(LL)(n-son)*2;
ans[x]+=(LL)(sum-1)*(LL)(son-sum);
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;scanf("%d %d",&x,&y);
insert(x,y);insert(y,x);
}
cnt=n;
memset(v,false,sizeof(v));
memset(dfn,-1,sizeof(dfn));
memset(g,false,sizeof(g));
dfs(1);
for(int x=1;x<=n;x++)
if(g[x])
for(int i=0;i<V[x].size();i++) ins(x,V[x][i]),ins(V[x][i],x);
if(g[1]) solve(1,0);
else solve(bel[1],0);
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]+(LL)(n-1)*2);
}