专栏文章

三元环计数学习笔记 || CF985G Team Players

CF985G题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqtilin
此快照首次捕获于
2025/12/04 10:29
3 个月前
此快照最后确认于
2025/12/04 10:29
3 个月前
查看原文
本文着重讲解三元环计数问题。

三元环计数

题意

给你 nn 个点 mm 条边的无向图,求三元环的个数。m2×105m\le 2\times10^5

题解

先考虑暴力。
枚举三元环中的其中一个点 uu,再枚举 uu 邻域中的一个点 vv,再枚举 vv 邻域中的一个点 ww,判断 ww 是否在 uu 的邻域中。
枚举 uuvv 实际上就是枚举了图中的边,所以暴力的时间复杂度是 O(m2)O(m^2) 的。
我们考虑给无向边定向,把无向图变成 DAG。
我们按照度数把点排序,度数小的连向度数大的。为了使图为 DAG,当度数相同时,编号小的连向编号大的,不然可能连出环。
我们发现按度数连边,每个点的出度不会很大。
  • 当点的度数 m\le \sqrt m 时,出度也 m\le \sqrt m
  • 当点的度数 >m> \sqrt m 时,假设出度 >m> \sqrt m,那么就有至少 m\sqrt m 个点的度数 >m> \sqrt m,显然矛盾。
所以每个点的出度都 m\le \sqrt m
接下来我们只需要去统计形如 uv,vw,uwu\to v,v\to w,u\to w 的三元环,枚举 ww 的这一步就优化成了 O(m)O(\sqrt m)
总时间复杂度为 O(mm)O(m\sqrt m)

例题 CF985G Team Players

题意

给你 nn 个点 mm 条边的无向图。
如果一个点的三元组 (i,j,k) (i<j<k)(i,j,k)~(i<j<k) 两两无边,那么它的贡献为 A×i+B×j+C×kA\times i+B\times j+C\times k
求出所有三元组的贡献和。

题解

题解中点的编号从 11 开始。
直接做边太多了,考虑容斥。分四种情况考虑。
  1. 边数 0\ge0
    • 直接暴力数三元组即可。
    • 贡献为 i=1ni×A×(ni2)+i=1ni×B×(i1)×(ni)+i=1ni×C×(i12)\sum\limits_{i=1}^ni\times A\times \dbinom{n-i}{2}+\sum\limits_{i=1}^ni\times B\times (i-1)\times(n-i)+\sum\limits_{i=1}^ni\times C\times \dbinom{i-1}{2}
    • 时间复杂度 O(n)O(n)
  2. 边数 1\ge 1
    • 枚举这条边 (u,v)(u,v),钦定 u<vu<v,考虑第三个点 ww 的位置。
    • w<uw<u 时,贡献为 w=1u1w×A+u×B+v×C=(u1)×(u×B+v×C)+u×(u1)2×A\sum\limits_{w=1}^{u-1}w\times A+u\times B+v\times C=(u-1)\times (u\times B+v\times C)+\cfrac{u\times(u-1)}{2}\times A
    • u<w<vu<w<v 时,贡献为 w=u+1v1u×A+w×B+v×C=(uv1)×(u×A+v×C)+(u+v)×(uv1)2×B\sum\limits_{w=u+1}^{v-1}u\times A+w\times B+v\times C=(u-v-1)\times (u\times A+v\times C)+\cfrac{(u+v)\times(u-v-1)}{2}\times B
    • v<wv<w 时,贡献为 w=v+1nu×A+v×B+w×C=(nv)×(u×A+v×B)+(v+1+n)×(nv)2×C\sum\limits_{w=v+1}^{n}u\times A+v\times B+w\times C=(n-v)\times (u\times A+v\times B)+\cfrac{(v+1+n)\times(n-v)}{2}\times C
    • 时间复杂度 O(m)O(m)
  3. 边数 2\ge 2
    • 枚举两条边的交点 uu,枚举 uu 邻域中的点 vv,考虑第三个点 ww 的位置。钦定 w<vw<v
    • rkrk 为邻域中编号小于 uu 的点的数量,iivv 在邻域中的排名,cntr=iN(u),irkicntr=\sum\limits_{i\in N(u),i\le rk}icntv=iN(u),i<vicntv=\sum\limits_{i\in N(u),i<v}i
    • wvuw\le v\le u 时,贡献为 wN(u),w<vw×A+v×B+u×C=(i1)×(v×B+u×C)+cntvA\sum\limits_{w\in N(u),w<v}w\times A+v\times B+u\times C=(i-1)\times(v\times B+u\times C)+cntv*A
    • wuvw\le u\le v 时,贡献为 wN(u),w<uw×A+u×B+v×C=rk×(u×B+v×C)+cntrA\sum\limits_{w\in N(u),w<u}w\times A+u\times B+v\times C=rk\times(u\times B+v\times C)+cntr*A
    • uwvu\le w\le v 时,贡献为 wN(u),u<w<vu×A+w×B+v×C=(vrk1)×(u×A+v×C)+(cntvcntr)B\sum\limits_{w\in N(u),u<w<v}u\times A+w\times B+v\times C=(v-rk-1)\times(u\times A+v\times C)+(cntv-cntr)*B
    • 时间复杂度 O(m)O(m)
  4. 边数 3\ge 3
    • 其实就是三元环计数。时间复杂度 O(mm)O(m\sqrt m)
简单容斥可得 ANS=Cnt0Cnt1+Cnt2Cnt3ANS=Cnt_0-Cnt_1+Cnt_2-Cnt_3

代码

CPP
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int N=2e5+10;
int n,m,d[N],vis[N];
ll C0,C1,C2,C3,A,B,C;
int fst[N<<1],to[N<<1],nxt[N<<1],ecnt;
void adde(int u,int v){
	ecnt++;
	to[ecnt]=v;
	nxt[ecnt]=fst[u];
	fst[u]=ecnt;
}
struct edge{int u,v;}E[N];
vector<int>e[N];
int main(){
	cin>>n>>m>>A>>B>>C;
	for(int i=1;i<=n;i++){//0
		C0+=(ll)(n-i)*(n-i-1)/2*A*(i-1);
		C0+=(ll)(i-1)*(n-i)*B*(i-1);
		C0+=(ll)(i-1)*(i-2)/2*C*(i-1);
	}
	for(int i=1;i<=n;i++)e[i].push_back(0);
	for(int i=1,u,v;i<=m;i++){//1
		cin>>u>>v;u++,v++;
		d[u]++,d[v]++;
		E[i]=(edge){u,v};
		e[u].push_back(v);
		e[v].push_back(u);
		if(u>v)swap(u,v);
		C1+=(u-1)*((u-1)*B+(v-1)*C)+(ll)(u-2)*(u-1)/2*A;
		C1+=(v-u-1)*((u-1)*A+(v-1)*C)+(ll)(v+u-2)*(v-u-1)/2*B;
		C1+=(n-v)*((u-1)*A+(v-1)*B)+(ll)(v+n-1)*(n-v)/2*C;
	}
	for(int i=1;i<=n;i++)sort(e[i].begin(),e[i].end());
	for(int u=1;u<=n;u++){//2
		ll rk=0,cntr=0,cnt=0;
		for(int i=1;i<=d[u];i++){
			if(e[u][i]<u)rk=i,cntr+=e[u][i]-1;
			else break;
		}
		for(int i=1;i<=d[u];i++){
			int v=e[u][i];
			if(v<u)C2+=(i-1)*((u-1)*C+(v-1)*B)+cnt*A;
			else{
				C2+=(i-rk-1)*((u-1)*A+(v-1)*C)+(cnt-cntr)*B;
				C2+=rk*((u-1)*B+(v-1)*C)+cntr*A;
			}
			cnt+=v-1;
		}
	}
	for(int i=1;i<=m;i++){
		if(d[E[i].u]<d[E[i].v]||(d[E[i].u]==d[E[i].v]&&E[i].u<E[i].v))adde(E[i].u,E[i].v);//注意这一行 
		else adde(E[i].v,E[i].u);
	}
	for(int u=1;u<=n;u++){//3
		for(int i=fst[u];i;i=nxt[i])vis[to[i]]=1;
		for(int i=fst[u];i;i=nxt[i]){
			int v=to[i];
			for(int j=fst[v];j;j=nxt[j]){
				int w=to[j];
				if(vis[w])C3+=(min({u,v,w})-1)*A+(u+v+w-min({u,v,w})-max({u,v,w})-1)*B+(max({u,v,w})-1)*C;
			}
		}
		for(int i=fst[u];i;i=nxt[i])vis[to[i]]=0;
	}
	cout<<C0-C1+C2-C3;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...