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