BZOJ5289 HNOI/AHOI2018排列(贪心+堆)
题面描述的相当绕,其实就是如果ai=j,重排后ai要在aj之后。同时每个ai有附属属性wi,要求最大化重排后的Σiwi。
容易发现这事实上构成一张图,即由j向i连边。由于每个点入度为1或0,该图是基环外向树森林,并且如果图中有环显然无解,所以这张图就是个森林。把0也看做一个点后变成一棵树。由于其是基环树判环并查集就够了。
问题变为对该树找一个删点的顺序使价值最大,要求删了父亲才能删儿子。显然应该尽量先删价值小的,但直接贪心肯定不对。
如果树中的最小值的父亲此时已经被删,立即将其删除一定是最优的。那么不妨考虑将这两个点合并。稍微推一下式子可以发现合并后用权值平均值作为新权值(不是贡献)即可。堆维护。
- #include<iostream>
- #include<cstdio>
- #include<cmath>
- #include<cstdlib>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<cassert>
- using namespace std;
- #define ll long long
- #define N 500010
- char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
- int gcd(int n,int m){return m==?n:gcd(m,n%m);}
- int read()
- {
- int x=,f=;char c=getchar();
- while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
- while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
- return x*f;
- }
- int n,a[N],fa[N],f[N],p[N],t;
- ll ans;
- bool flag[N];
- struct data{int to,nxt;
- }edge[N];
- struct data2
- {
- int id,cnt;ll tot,val;
- bool operator <(const data2&a) const
- {
- return tot*a.cnt>a.tot*cnt;
- }
- bool operator !=(const data2&a) const
- {
- return id!=a.id||cnt!=a.cnt||tot!=a.tot||val!=a.val;
- }
- }lazy[N];
- priority_queue<data2> q;
- void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
- int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
- void dfs(int k)
- {
- for (int i=p[k];i;i=edge[i].nxt)
- f[edge[i].to]=k,dfs(edge[i].to);
- }
- int main()
- {
- #ifndef ONLINE_JUDGE
- freopen("bzoj5289.in","r",stdin);
- freopen("bzoj5289.out","w",stdout);
- const char LL[]="%I64d\n";
- #else
- const char LL[]="%lld\n";
- #endif
- n=read();
- for (int i=;i<=n;i++) fa[i]=i;
- for (int i=;i<=n;i++)
- {
- int x=read();addedge(x,i);
- int p=find(x),q=find(i);
- if (p!=q) fa[q]=p;else {cout<<-;return ;}
- }
- dfs();
- for (int i=;i<=n;i++)
- {
- a[i]=read(),fa[i]=i;
- lazy[i]=(data2){i,,a[i],a[i]};q.push(lazy[i]);
- }
- flag[]=;fa[]=;int cnt=;
- for (int i=;i<=n;i++)
- {
- while (q.top()!=lazy[q.top().id]) q.pop();
- data2 x=q.top();q.pop();int u=find(f[x.id]);fa[x.id]=u;
- if (flag[u]) ans+=x.val+cnt*x.tot,cnt+=x.cnt,flag[x.id]=;
- else lazy[u].val+=lazy[u].cnt*x.tot+x.val,lazy[u].id=u,lazy[u].cnt+=x.cnt,lazy[u].tot+=x.tot,q.push(lazy[u]);
- }
- cout<<ans;
- return ;
- }
BZOJ5289 HNOI/AHOI2018排列(贪心+堆)的更多相关文章
- [HNOI/AHOI2018]排列 贪心
题面 题解: 把题面的限制换成中文: 如果排在第k位的下标 = 排在第j位的值 ,那么k < j 换一个描述方式: 一个值为x的数要排在第x个数后面. 再换一个描述方式: \(fa[i] = a ...
- 【LG4437】[HNOI/AHOI2018]排列
[LG4437][HNOI/AHOI2018]排列 题面 洛谷 题解 题面里这个毒瘤的东西我们转化一下: 对于\(\forall k,j\),若\(p_k=a_{p_j}\),则\(k<j\). ...
- 洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)
题面传送门 开始 WA ycx 的遗产(bushi 首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_ ...
- 【洛谷 P4437】 [HNOI/AHOI2018]排列(贪心,堆)
题目链接 如果\(j<=k,a_{p[j]}!=p[k]\)可以理解为如果\(a_{p[j]}=p[k]\),那么\(k\)一定要放在\(j\)前面,也就是\(a_j\)在\(j\)前面. 于是 ...
- BZOJ5289 & 洛谷4437:[HNOI/AHOI2018]排列——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5289 https://www.luogu.org/problemnew/show/P4437 考虑 ...
- [HNOI/AHOI2018]排列
[Luogu4437] 如果\(a[i]=j\)则序列\(p[]\)中\(j\)必须排在\(i\)前面,如果\(j\)不在范围内则不管,求一个式子\(\sum_{i=1}^n iw_{p[i]}\)的 ...
- Poj2054 color a tree && [HNOI/AHOI2018]排列
https://zybuluo.com/ysner/note/1120723 题面 原题 某省选强化题 大致意思是给你一颗树,选父亲后才能选儿子. 每个点对答案的贡献为你在第几次选这个点 × 该点权值 ...
- luogu P4437 [HNOI/AHOI2018]排列
luogu 问题本质是把\(a_i\)作为\(i\)的父亲,然后如果有环就不合法,否则每次要取数,要满足取之前他的父亲都被取过(父亲为0可以直接取),求最大价值 贪心想法显然是要把权值大的尽量放在后面 ...
- 【BZOJ5289】[HNOI2018]排列(贪心)
[BZOJ5289][HNOI2018]排列(贪心) 题面 BZOJ 洛谷 题解 这个限制看起来不知道在干什么,其实就是找到所有排列\(p\)中,\(p_k=x\),那么\(k<j\),其中\( ...
随机推荐
- 常见面试算法题JS实现-仅用递归函数和栈操作逆序一个栈
前言: 因为JAVA和JS语言特性的不同,有些东西在JAVA中可能需要一些技巧和手段才能实现的复杂程序,但是在JS中可能就是天然存在的,所以这套书里面的题目不会全部用JS去实现一遍,因为可能JS的实现 ...
- async/await工作机制探究--NodeJS
ES6中的async/await让Promise变得更加简便,通常await处理的链式Promise会包裹在函数中,返回结果仍然是一个Promise对象. 但是当await直接处理链式Promise时 ...
- Winfrom Panel Scroll End 的实现
场景:在一个panel里面有非常多的自定义绘制的控件,在拖拉滚动条的时候,控件的画面上有残影 不知道大家遇到过这种情况没,一直做web的winform经验太少,有更好的解决办法请贡献 首先放出我的解决 ...
- 在server 2003中搭建域服务(Http NTLM 代理)
在server 2003中搭建域服务(Http NTLM 代理) 在windows server 2003 X64中搭建域服务的操作. 可参考百度经验:http://www.cnblogs.com/z ...
- Windows下Redis安装及使用
1.下载安装Redis(安装直接下一步就行,此步骤省略) Redis-x64-3.2.100.exe 2.Redis使用 安装目录如下: ①cmd启动redis: ②将redis安装为服务 此时如果安 ...
- OpenGL学习笔记(1) 画一个三角形
最近找实习有一丢丢蛋疼,沉迷鬼泣5,四周目通关,又不想写代码,写篇笔记复习一下,要好好学图形学啊 用OpenGL画一个三角形 项目的简介 记录一下跟着learnOpenGL学习的过程 笔记里的代码放在 ...
- Python创建虚拟环境
用于创建和管理虚拟环境的模块称为 venv.venv 通常会安装你可用的最新版本的 Python.如果您的系统上有多个版本的 Python,您可以通过运行 python3 或您想要的任何版本来选择特定 ...
- Elasticsearch的停用词(stopwords)
1.问题 在使用搜索引擎(Elasticsearch或Solr)作为应用的后台搜索平台的时候,会遇到停用词(stopwords)的问题. 在信息检索中,停用词是为节省存储空间和提高搜索效率,处理文本时 ...
- vscode调试js,安装了nodejs之后还出现无法在Path上找到运行时的node
vscode 调试js,安装了nodejs之后还出现无法在Path上找到运行时的node. 重启vscode解决
- nohup命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/hfismyangel/article/details/80258126 1.nohup 用途:不挂断地运行命令. 语法:n ...