Luogu P6815 [PA2009] Cakes 题解

P6815 [PA2009] Cakes

三元环计数题。

无向图三元环计数分为三步:

\(1\) :给所有无向边重定向。记录每个点的度数,度数大的点指向度数小的点。如果度数相同,编号小的点指向编号大的点。最后这个图是有向无环图。

\(2\) :打标记。对于图中每一个点 \(u\),将其相邻的点标记可以被 \(u\) 到达。

\(3\) :统计答案。对于图中每一个点 \(u\),遍历其可以相邻的点 \(v\),如果 \(v\) 相邻的点 \(w\) 被标记可以被 \(u\) 到达,那么 \((u,v,w)\) 构成一个三元环。三元环不会被重复计算。

在这一题中,我们只需要对无向图三元环计数算法的第三步略微改动,当我们发现 \((u,v,w)\) 构成一个三元环时,将答案增加 \(\max(a_u,a_v,a_w)\) 即可。

由于无向图三元环计数算法复杂度为 \(O(m\sqrt{m})\),所以这个算法的时间复杂度为 \(O(m\sqrt{m})\)

本题卡邻接表的常数,注意常数影响。

#include <bits/stdc++.h>
using namespace std;
struct edge
{
	int v,nxt;
}e[600000];
int n,m,a[200000],h[200000],b[200000],ind[200000],u[400000],v[400000],cnt=0;
long long ans=0;
void add_edge(int u,int v)
{
	e[++cnt].nxt=h[u];
	e[cnt].v=v;
	h[u]=cnt;
}

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++)u[i]=read(),v[i]=read(),ind[u[i]]++,ind[v[i]]++;
	for(int i=1;i<=m;i++)
	    if((ind[u[i]]>ind[v[i]])||(ind[u[i]]==ind[v[i]]&&u[i]<v[i]))add_edge(u[i],v[i]);
	    else add_edge(v[i],u[i]);
	for(int i=1;i<=n;i++)
	    {
	    for(int j=h[i];j;j=e[j].nxt)b[e[j].v]=i;
	    for(int j=h[i];j;j=e[j].nxt)
	        {
	        int ad=max(a[i],a[e[j].v]);
	        for(int k=h[e[j].v];k;k=e[k].nxt)
	            if(b[e[k].v]==i)ans+=max(ad,a[e[k].v]);
	        }
	    }
	printf("%lld",ans);
	return 0;
}
posted @ 2025-02-14 18:31  w9095  阅读(9)  评论(0)    收藏  举报