【HNOI2018】排列

【HNOI2018】排列

img
img
img
img

神仙贪心题。

题目说这么大堆东西就是想告诉你这是个森林,选了\(v\)的父亲后才能选\(v\)

我们设\(w_v\)\(v\)所在联通块权值和,\(size_v\)表示\(v\)所在联通块的大小。

我们先考虑单点\(v\)。如果\(v\)是最小的点,那么我们尽量早地将它选了。也就是在选了\(v\)的父亲后就立即选\(v\)。所以我们可以将\(v\)与他的父亲合为一个联通块。

这个结论对于联通块也是成立的,只不过我们要比较平均值。

对于联通块\(u\),\(v\),如果\(u\)的优先级大于\(v\),则:
\[ w_u+size_u\cdot w_v<w_v+size_v\cdot w_u\\ \Rightarrow \frac{w_u}{size_u}<\frac{w_v}{size_v} \]

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 500005
#define eps 1e-10

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

int n;
int a[N];
ll w[N];
int f[N],fa[N];
int Getf(int v) {return v==f[v]?v:f[v]=Getf(f[v]);}
int size[N];

struct node {
    ll w,s;
    int id;
    node() {w=s=id=0;}
    node(ll x,ll z,int y) {w=x,s=z,id=y;}
    bool operator <(const node &a)const {
        if(w*a.s!=a.w*s) return w*a.s>a.w*s;
        if(w!=a.w) return w<a.w;
        if(s!=a.s) return s<a.s;
        return id>a.id;
    }
};
bool operator ==(const node &a,const node &b) {return a.id==b.id&&a.w==b.w&&a.s==b.s;}

struct heap {
    priority_queue<node>add,del;
    void Insert(node tem) {add.push(tem);}
    void Pop() {while(del.size()&&(del.top())==(add.top())) del.pop(),add.pop();}
    void Del(node tem) {
        Pop();
        del.push(tem);
    }
    node Top() {
        Pop();
        return add.top();
    }
}S;
set<node>s;
node tem;

int main() {
    n=Get();
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=n;i++) a[i]=Get();
    for(int i=1;i<=n;i++) w[i]=Get();
    for(int i=1;i<=n;i++) {
        if(Getf(a[i])==Getf(i)) {cout<<-1;return 0;}
        f[Getf(a[i])]=Getf(i);
    }
    ll ans=0;
    for(int i=0;i<=n;i++) f[i]=i;
    for(int i=1;i<=n;i++) {
        size[i]=1;
        S.Insert(node(w[i],1,i));
        ans+=w[i];
    }
    for(int i=1;i<=n;i++) {
        tem=S.Top();
        S.Del(tem);
        int now=tem.id;
        int fa=Getf(a[now]);
        if(fa) S.Del(node(w[fa],size[fa],fa));
        ans+=size[fa]*w[now];
        w[fa]+=w[now];
        size[fa]+=size[now];
        if(fa) S.Insert(node(w[fa],size[fa],fa));
        f[now]=Getf(fa);
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hchhch233/p/10539851.html