P6815 [PA2009] Cakes(三元环计数)

[PA2009] Cakes

题目描述

一个有 \(n\) 个点 \(m\) 条边的无向图,每个点有一个点权 \(a\)

对于任意一个三元环 \((i,j,k)(i<j<k)\),它的贡献为 \(\max (a_i,a_j,a_k)\)

求所有三元环的贡献和。

我们可以给无向边定向,具体的做法是
度数小的连向度数大的。
度数相等,编号小的连向大的。
然后枚举i的每个出点j,进行标记。
再对每个j枚举出点k,若k被i标记,则形成一个三元环。

首先这是一个DAG,正确性是显然的。
考虑分析复杂度。

\(d_i\)为原图中度数,\(id_i\)\(od_i\)表示新图中的入度和出度。
考虑j点
1.原图中\(d_j<\sqrt{m}\),新图中\(od_j<\sqrt{m}\)
2.原图中\(d_j>\sqrt{m}\),由于j只会向度数大于它的点连边。\(od_i<\sqrt{m}\)
所以复杂度是\(O(m\sqrt{m})\)级别的。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<bitset>
#include<cmath>
#include<set>
#include<unordered_map>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define A puts("Yes")
#define B puts("No")
using namespace std;
typedef double db;
typedef long long ll;
//typedef __int128 i128;
const int N=3e5+10;
//const int S=1e5+5;
//const int inf=1ll<<60;
const int inf=1<<29;
const ll mo=1e9+7;
struct node{
	int x,y;
};
node a[N];
int n,d[N],m,x,y;
vector<int> e[N];
int bz[N];
ll c[N];
int main()
{
//	freopen("data.in","r",stdin);
	
	scanf("%d %d",&n,&m);
	fo(i,1,n) scanf("%lld",&c[i]);
	
	fo(i,1,m) {
		scanf("%d %d",&x,&y);
		a[i]=(node){x,y};
		d[x]++; d[y]++;
	}
	
	fo(i,1,m) {
		x=a[i].x; y=a[i].y;
		if (d[x]!=d[y]) {
			if (d[x]>d[y]) swap(x,y);
			e[x].emplace_back(y);
		}
		else {
			if (x>y) swap(x,y);
			e[x].emplace_back(y);
		}
	}
	
	ll ans=0;
	fo(i,1,n) {
		for (int v:e[i]) bz[v]=i;
		for (int j:e[i]) for (int k:e[j]) {
			if (bz[k]==i) {
				ans+=max(c[i],max(c[j],c[k]));
			}
		}
	}
	printf("%lld",ans);
	
	return 0;
}

	
 
 
posted @ 2024-01-18 09:48  gan_coder  阅读(20)  评论(0)    收藏  举报