[bzoj3498]Cakes

题目描述

N个点m条边,每个点有一个点权a。
对于任意一个三元环 (ijk)i<j<k ,它的贡献
为max(ai,aj,ak)
求所有三元环的贡献和。
N<100000,,m<250000。

瞎做

我们都知道一个定理就是一个图,枚举不比一个点度数小的点只有根号m个。
因此我们可以以度数来定义优先级,度数大优先级高,相同度数编号越大优先级越高。
对于一个三元环,我们希望在它优先最高的点上统计到它。
枚举一条边,设连接了u和v,因为是无向边,注意不要枚举重复,因此这里设u的优先级要比v小。
接下来我们就需要找到所有的w,使得w与u和v都相连且w优先级比u和v都高。
根据定理,这样的w只有根号个,我们直接枚举与u相连的优先级高于u的点,以及与v相连的优先级高于v的点,这里的交集是合法的,就能统计答案。

#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define max(a,b) (a>b?a:b)
using namespace std;
typedef long long ll;
const int maxn=100000+10,maxm=250000+10;
int h[maxn],go[maxm*2],nxt[maxm*2];
int h2[maxn],g2[maxm*2],n2[maxm*2];
int a[maxn],d[maxn];
bool bz[maxn];
int i,j,k,l,r,t,n,m,tot,top,cnt;
ll ans;
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-'0';
        ch=getchar();
    }
    return x*f;
}
void add(int x,int y){
    d[y]++;
    go[++tot]=y;
    nxt[tot]=h[x];
    h[x]=tot;
}
void add2(int x,int y){
    g2[++top]=y;
    n2[top]=h2[x];
    h2[x]=top;
}
bool cmp(int x,int y){
    return d[x]int main(){
    n=read();m=read();
    fo(i,1,n) a[i]=read();
    fo(i,1,m){
        j=read();k=read();
        add(j,k);add(k,j);
    }
    fo(i,1,n){
        t=h[i];
        while (t){
            if (cmp(i,go[t])) add2(i,go[t]);
            t=nxt[t];
        }
    }
    fo(i,1,n){
        t=h[i];
        while (t){
            j=go[t];
            if (cmp(i,j)){
                r=h2[i];
                while (r){
                    bz[g2[r]]=1;
                    r=n2[r];
                }
                r=h2[j];
                while (r){
                    if (bz[g2[r]]==1) ans+=(ll)max(a[i],max(a[j],a[g2[r]]));
                    r=n2[r];
                }
                r=h2[i];
                while (r){
                    bz[g2[r]]=0;
                    r=n2[r];
                }
            }
            t=nxt[t];
        }
    }
    printf("%lld\n",ans);
}

你可能感兴趣的:(暴力)