zoukankan      html  css  js  c++  java
  • 【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_ucdot w_v<w_v+size_vcdot 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;
    }
    
    
  • 相关阅读:
    通过队列实现进程间的通信(使用阻塞方式调用func函数)
    Scrapy 项目:QuotesBot
    数据分析_找数据参考网站
    Matplotlib 图表绘制工具学习笔记
    Python算法_斐波那契数列(10)
    Python算法_排序数组(09)
    Python数据结构与算法_反转字符串(08)
    Python算法_爬楼梯(08)
    Python数据结构与算法_搜索插入位置(07)
    Python数据结构与算法_删除排序数组中的重复项(06)
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10539851.html
Copyright © 2011-2022 走看看