版权声明:转载请注明原出处啦(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/82938175
题目:BZOJ1123.
题目大意:给定一张图,输出当与点i的相连的边都被去掉后,有多少个无需点对(x,y)不连通.
这道题其实不难.
首先我们知道,一个点i的所有边去掉后,这个点i肯定与其它点不相连了,所以不相连的对数先加上n-1.
然后我们发现这个点i若不是割点,那么对数就只有这么点.但是如果是割点,我们发现它的独立子树(即与点i的父亲不在一个联通块里的子树)与它的父亲所在的联通块之间会有对数.
我们设一棵独立子树的大小为size,则这个独立子树会产生的对数为.
而我们设点i父亲所在连通块的大小为size,我们发现会产生的对数也为.
其实蓝书上的公式跟这个公式是等价的.
而如何求一棵子树以j为根是不是独立子树?我们只要判断一棵子树是否有非树边连向点i的父亲所在连通块内的节点,即是否满足.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000,M=500000;
struct side{
int y,next;
}e[M*2+9];
struct node{
LL ans;
int dfn,low,size;
bool cut;
}d[N+9];
int n,m,top=1,num,root=1,lin[N+9];
void ins(int X,int Y){
e[++top].y=Y;
e[top].next=lin[X];
lin[X]=top;
}
void tarjan(int k){
int flag=0,size=0;
d[k].size=1LL;
d[k].ans=LL(n-1);
d[k].dfn=d[k].low=++num;
for (int i=lin[k];i;i=e[i].next){
int y=e[i].y;
if (!d[y].dfn){
tarjan(y);
d[k].low=min(d[y].low,d[k].low);
d[k].size+=d[y].size;
if (d[y].low>=d[k].dfn){
flag++;
if (k^root||flag>1) d[k].cut=1;
d[k].ans+=1LL*d[y].size*LL(n-d[y].size);
}else size+=d[y].size;
}else d[k].low=min(d[k].low,d[y].dfn);
}
size+=LL(n-d[k].size);
d[k].ans+=1LL*size*LL(n-size);
}
Abigail into(){
scanf("%d%d",&n,&m);
int x,y;
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
}
Abigail work(){
tarjan(1);
}
Abigail outo(){
for (int i=1;i<=n;i++)
printf("%lld\n",d[i].ans);
}
int main(){
into();
work();
outo();
return 0;
}
m写成了n调了一个晚上...