这是一道水题。
首先对原图进行边的双连通分量,那么很显然,在两个不同的联通分量中的点对就是不安全的点对,同在相同的连通分量中的点对就是安全点对。
那么假如有两个连通分量互相连边,那么就会有一群连通分量合并为一个大的连通分量。
那么要如何实现呢?
这是一个很显然而且很经典的想法。
先对原图用tarjan缩点(每个点存储它点的个数),然后缩完点之后就会变成一个树。之后在这个树上倍增就能得到答案。
但是要怎么处理两两点相乘的和?
比如说现在有四个点的权值分别为a,b,c,d,要快速得到两两之间点的乘积,用: (a+b+c+d)2−a2−b2−c2−d2 就可以了,而且还刚好是两倍。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
#define rep1(i,a) for(i=first1[a];i;i=next1[i])
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=400007;
int i,j,k,l,t,n,m,cas;
int first[maxn*2],next[maxn*2],last[maxn*2],num;
int first1[maxn*2],next1[maxn*2],last1[maxn*2],num1;
int low[maxn],dfn[maxn],stack[maxn],dfx,tou;
int size[maxn],a[maxn],hhh;
int b[maxn],c[maxn];
bool az[maxn],bz[maxn],cz[maxn*2];
ll ans,zhi,zhi1,g[maxn][21],p[maxn][21];
int deep[maxn],f[maxn][21];
void add(int x,int y){
last[++num]=y;next[num]=first[x],first[x]=num;
}
void add1(int x,int y){
last1[++num1]=y;next1[num1]=first1[x],first1[x]=num1;
}
void dfs1(int x,int y){
int i;
deep[x]=deep[y]+1,f[x][0]=y;
g[x][0]=size[y];p[x][0]=size[y]*size[y];
rep1(i,x){
if(last1[i]!=y){
dfs1(last1[i],x);
}
}
}
int lca(int x,int y){
int i;if(deep[x]y])swap(x,y);zhi=zhi1=0;
fod(i,20,0)if(deep[f[x][i]]>deep[y])zhi+=g[x][i],zhi1+=p[x][i],x=f[x][i];
if(deep[x]!=deep[y])zhi+=g[x][0],zhi1+=p[x][0],x=f[x][0];
fod(i,20,0)if(f[x][i]!=f[y][i])zhi+=g[x][i]+g[y][i],zhi1+=p[x][i]+p[y][i],x=f[x][i],y=f[y][i];
if(x!=y){
zhi+=g[x][0];
zhi1+=p[x][0];
return f[x][0];
}
return x;
}
void tarjan(int x){
int i;
dfn[x]=low[x]=++dfx;
stack[++stack[0]]=x;
bz[x]=az[x]=1;
rep(i,x){
if(!cz[(i-1)]&&!cz[(i-1)^1]){
cz[i-1]=1;
if(!bz[last[i]]){
tarjan(last[i]);
low[x]=min(low[x],low[last[i]]);
}
else if(az[last[i]])low[x]=min(low[x],dfn[last[i]]);
}
// else if(az[last[i]])low[x]=min(low[x],dfn[last[i]]);
}
if(low[x]==dfn[x]){
hhh++;
while(stack[stack[0]+1]!=x){
az[stack[stack[0]]]=0;
a[stack[stack[0]]]=hhh;
stack[0]--;
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&cas);
fo(i,1,m){
scanf("%d%d",&l,&t);b[i]=l,c[i]=t;
add(l,t),add(t,l);
}
/* if(n==m+1){
dfs1(1,0);
fo(j,1,20){
fo(i,1,n)f[i][j]=f[f[i][j-1]][j-1];
}
for(;cas;cas--){
scanf("%d%d",&k,&l);
int o=lca(k,l);
t=deep[k]+deep[l]-2*deep[o]+1;
ans+=t*(t-1);
}
printf("%lld\n",ans);
}
else{*/
fo(i,1,n){
if(!bz[i]){
tarjan(i);
}
}
fo(i,1,n){
size[a[i]]++;
}
fo(i,1,m){
if(a[b[i]]!=a[c[i]]){
add1(a[b[i]],a[c[i]]);
add1(a[c[i]],a[b[i]]);
}
}
tou=a[1];
dfs1(tou,0);
fo(j,1,20){
fo(i,1,hhh){
f[i][j]=f[f[i][j-1]][j-1];
g[i][j]=g[f[i][j-1]][j-1]+g[i][j-1];
p[i][j]=p[f[i][j-1]][j-1]+p[i][j-1];
}
}
for(;cas;cas--){
scanf("%d%d",&k,&l);
if(deep[a[k]]if(a[k]!=a[l]){
int o=lca(a[k],a[l]);
zhi+=size[a[k]],zhi1+=(ll)size[a[k]]*size[a[k]];
if(o!=a[l])zhi+=size[a[l]],zhi1+=(ll)size[a[l]]*size[a[l]];
ans+=zhi*zhi-zhi1;
}
}
printf("%lld\n",ans);
// }
}