• 【5289】【HNOI2018】—排列(语文题)


    传送门

    看了20分钟硬是没看懂他在说什么
    膜了题解之后
    实际上就是一棵树,求一个代价最大的拓扑序
    发现对于一个点选了之后会有一些更小的儿子必须选
    即对于2个点i,ji,j
    满足wisi+wj(si+sj)=>wi/si<wj/sjwi*si+wj*(si+sj)=>wi/si<wj/sj

    用一个堆维护每一次找最小的一个就行了

    #include<bits/stdc++.h>
    #include<ext/pb_ds/priority_queue.hpp>
    using namespace std;
    using namespace __gnu_pbds;
    #define re register
    #define ll long long
    #define db long double
    #define pii pair<db,int>
    typedef __gnu_pbds::priority_queue <pii,greater<pii>,pairing_heap_tag> Heap;
    typedef Heap::point_iterator it;
    
    const int RLEN=1<<20|1;
    inline char nc() {
        static char ibuf[RLEN],*ib,*ob;
        (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ib==ob) ? -1 : *ib++;
    }
    inline int read() {
        char ch=nc(); int i=0,f=1;
        while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
        while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
        return i*f;
    }
    const int N=500005;
    int n,a[N],fa[N],f[N],w[N],dfn;
    bool vis[N],o[N];
    ll ans,sum[N],siz[N];
    int adj[N],nxt[N<<1],to[N<<1],cnt,tot;
    it pos[N];Heap q;
    inline void addedge(int u,int v){
    	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    int find(int x){
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    bool dfs(int u){
    	++dfn,vis[u]=true,fa[u]=u;
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];
    		if(vis[v])return false;
    		f[v]=u;if(!dfs(v))return false;
    	}
    	return true;
    }
    int main(){
    	n=read();
    	for(re int i=1;i<=n;++i)a[i]=read(),addedge(a[i],i);
    	for(re int i=1;i<=n;++i)w[i]=read(),sum[i]=w[i],siz[i]=1;siz[0]=1;
    	if(!dfs(0)||dfn!=n+1){puts("-1");return 0;}
    	for(re int i=0;i<=n;++i)pos[i]=q.push(pii((db)sum[i]/siz[i],i));
    	while(!q.empty()){
    		int u=q.top().second;q.pop();
    		if(!u||o[find(f[u])]){
    			ans+=tot*sum[u];
    			tot+=siz[u];
    			o[u]=1;
    		}
    		else{
    			int f1=find(f[u]);
    			ans+=siz[f1]*sum[u];
    			siz[f1]+=siz[u];
    			sum[f1]+=sum[u];
    			fa[u]=f1;
    			q.modify(pos[f1],pii((db)sum[f1]/siz[f1],f1));
    		}
    	}
    	cout<<ans;
    }
    
  • 相关阅读:
    Windows Azure 网站开发Stacks支持
    AzureDev 社区活动获奖者公布
    Android 改变窗口标题栏的布局
    cocos2d-x游戏开发系列教程-超级玛丽01-前言
    cocos2dx进阶学习之CCObject
    基于visual Studio2013解决算法导论之055拓扑排序
    查看某文件夹内文件大小
    vmstat命令
    uname 命令
    iostat命令
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145636.html
Copyright © 2020-2023  润新知