Luogu 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;
}

浙公网安备 33010602011771号