【JZOJ4784】Map

description


analysis

  • 正解tarjan+tarjan+tarjan+倍增

  • 首先考虑图为一棵树的情况,发现贡献即为(∑v[i])2−∑v[i]2(\sum v[i])^2-\sum v[i]^2(v[i])2v[i]2

  • 那么我们tarjantarjantarjan缩完点以后,原图就变成了一棵树

  • 用倍增维护点权和与点权的平方和,每次O(log⁡2n)O(\log_2n)O(log2n)边跳边统计即可

  • 时间复杂度O((n+q)log⁡2n)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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值