Jzoj4784 Map
这个题意很简单,就是问你连一条边会增加多少双联通点对
按照一般的方法,先用Tarjan缩点化为一颗树,每次连起来就在树上找路径统计答案
答案的统计方法,设树上节点i(原图的一个双联通块)的大小为v[i]
那么一条路径[x,y]的端点被连接起来,贡献应该是(Σv[i])^2-Σv[i]^2,其中i∈x~y的路径
这样的话可以用倍增或者树剖求lca来解决
码量比较大
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200010
#define LL long long
using namespace std;
struct Edge{ int u,v,nt; } G[N<<3];
int c=1,q,h[N],dfn[N],clk=0,Col=0;
int n,m,low[N],col[N],du[N]; bool b[N<<1];
inline void adj(int x,int y){
G[++c]=(Edge){x,y,h[x]}; h[x]=c;
G[++c]=(Edge){y,x,h[y]}; h[y]=c;
}
void tarjan(int u,int v){
clk++; low[v]=dfn[v]=clk;
for(int w,i=h[v];i;i=G[i].nt)
if((i&~1)!=(u&~1)){
if(!dfn[w=G[i].v]){
tarjan(i,w);
if(low[w]==dfn[w] || low[w]>dfn[v]){ b[i]=1; b[i^1]=1; }
else low[v]=min(low[v],low[w]);
} else low[v]=min(low[v],dfn[w]);
}
}
void dfs(int x,int u,int Cl){
col[x]=Cl; du[Cl]++;
for(int v,i=h[x];i;i=G[i].nt)
if((v=G[i].v)!=u&&!b[i]&&!col[v]) dfs(v,x,Cl);
}
struct Tree{
Edge G[N<<1]; int h[N],d[N],f[18][N],cnt; LL s1[N],s2[N];
//Tree(){ cnt=0; }
inline void adj(int x,int y){
G[++cnt]=(Edge){x,y,h[x]}; h[x]=cnt;
G[++cnt]=(Edge){y,x,h[y]}; h[y]=cnt;
}
void dfs(int x,int p){
d[x]=d[p]+1; f[0][x]=p;
s1[x]=s1[p]+du[x]; s2[x]=s2[p]+(LL)du[x]*du[x];
for(int j=1;j<18;++j)
f[j][x]=f[j-1][f[j-1][x]];
for(int v,i=h[x];i;i=G[i].nt)
if((v=G[i].v)!=p) dfs(v,x);
}
void build(){ dfs(1,0); }
void swim(int& x,int d){
for(int i=0;d;++i,d>>=1) if(d&1) x=f[i][x];
}
int gLca(int x,int y){
if(d[x]>d[y]) swap(x,y);
LL x1=0,x2=0;
swim(y,d[y]-d[x]);
if(x==y) return x;
for(int j=17;;){
for(;~j&&f[j][x]==f[j][y];--j);
if(j<0) return f[0][x];
x=f[j][x]; y=f[j][y];
}
}
LL query(int x,int y){
int p=gLca(x,y);
LL x1=s1[x]+s1[y]-2*s1[p]+du[p];
LL x2=s2[x]+s2[y]-2*s2[p]+(LL)du[p]*du[p];
return x1*x1-x2;
}
} T;
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int x,y,i=0;i<m;++i){
scanf("%d%d",&x,&y);
adj(x,y);
}
tarjan(0,1); T.cnt=0;
for(int i=1;i<=n;++i)
if(!col[i]) dfs(i,0,++Col);
for(int i=2;i<=c;i+=2)
if(col[G[i].u]!=col[G[i].v]) T.adj(col[G[i].u],col[G[i].v]);
T.build(); LL SS=0;
for(int x,y;q--;SS+=T.query(col[x],col[y])) scanf("%d%d",&x,&y);
for(printf("%lld\n",SS);;) return 0;
}