description
analysis
-
正解tarjan+tarjan+tarjan+倍增
-
首先考虑图为一棵树的情况,发现贡献即为(∑v[i])2−∑v[i]2(\sum v[i])^2-\sum v[i]^2(∑v[i])2−∑v[i]2
-
那么我们tarjantarjantarjan缩完点以后,原图就变成了一棵树
-
用倍增维护点权和与点权的平方和,每次O(log2n)O(\log_2n)O(log2n)边跳边统计即可
-
时间复杂度O((n+q)log2n)O((n+q)\log_2n)O((n+q)log2n)
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 400005
#define MAXM MAXN*2
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=last[a];i;i=next[i])
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll last[MAXM],next[MAXM],tov[MAXM];
ll b[MAXN],dfn[MAXN],low[MAXN],stack[MAXN],color[MAXN];
ll depth[MAXN],anc[MAXN][19],sum[MAXN][19],sqrsum[MAXN][19];
ll a[MAXM][2];
bool bz[MAXN];
ll n,m,q,tot=1,top,total,ans;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline ll sqr(ll x)
{
return x*x;
}
O3 inline void link(ll x,ll y)
{
if (x==y)return;
next[++tot]=last[x],last[x]=tot,tov[tot]=y;
}
O3 inline void tarjan(ll x,ll y)
{
low[x]=dfn[x]=++tot;
stack[++top]=x,bz[x]=1;
rep(i,x)if (i!=(y^1))
{
if (!dfn[tov[i]])tarjan(tov[i],i),low[x]=min(low[x],low[tov[i]]);
else if (bz[tov[i]])low[x]=min(low[x],dfn[tov[i]]);
}
if (low[x]==dfn[x])
{
total++;
for(;stack[top+1]!=x;top--)
{
ll k=stack[top];
color[k]=total,b[total]++,bz[k]=0;
}
}
}
O3 inline void dfs(ll x,ll y)
{
rep(i,x)if (tov[i]!=y)
{
depth[tov[i]]=depth[x]+1;
anc[tov[i]][0]=x;
sum[tov[i]][0]=b[tov[i]];
sqrsum[tov[i]][0]=sqr(b[tov[i]]);
dfs(tov[i],x);
}
}
O3 inline ll lca(ll x,ll y)
{
if (depth[x]<depth[y])swap(x,y);
fd(k,18,0)if (depth[anc[x][k]]>depth[y])x=anc[x][k];
if (depth[x]!=depth[y])x=anc[x][0];
fd(k,18,0)if (anc[x][k]!=anc[y][k])x=anc[x][k],y=anc[y][k];
return x==y?x:anc[x][0];
}
O3 int main()
{
freopen("T3.in","r",stdin);
n=read(),m=read(),q=read();
fo(i,1,m)
{
ll x=read(),y=read();
link(x,y),link(y,x);
a[i][0]=x,a[i][1]=y;
}
tot=0,tarjan(1,-1);
memset(last,0,sizeof(last)),memset(next,0,sizeof(next));
memset(tov,0,sizeof(tov)),tot=1;
fo(i,1,m)link(color[a[i][0]],color[a[i][1]]),link(color[a[i][1]],color[a[i][0]]);
depth[1]=1,dfs(1,0);
fo(j,1,18)
{
fo(i,1,n)
{
anc[i][j]=anc[anc[i][j-1]][j-1];
if (anc[i][j])sum[i][j]=sum[i][j-1]+sum[anc[i][j-1]][j-1],
sqrsum[i][j]=sqrsum[i][j-1]+sqrsum[anc[i][j-1]][j-1];
}
}
while (q--)
{
ll x=color[read()],y=color[read()],LCA=lca(x,y),cnt1=b[LCA],cnt2=sqr(b[LCA]);
if (x==y)continue;
fd(k,18,0)if (depth[anc[x][k]]>=depth[y])cnt1+=sum[x][k],cnt2+=sqrsum[x][k],x=anc[x][k];
fd(k,18,0)if (depth[anc[y][k]]>=depth[x])cnt1+=sum[y][k],cnt2+=sqrsum[y][k],y=anc[y][k];
fd(k,18,0)if (anc[x][k]!=anc[y][k])cnt1+=sum[x][k]+sum[y][k],cnt2+=sqrsum[x][k]+sqrsum[y][k],x=anc[x][k],y=anc[y][k];
if (x!=y)cnt1+=sum[x][0]+sum[y][0],cnt2+=sqrsum[x][0]+sqrsum[y][0],x=anc[x][0],y=anc[y][0];
ans+=sqr(cnt1)-cnt2;
}
printf("%lld\n",ans);
return 0;
}