题意

给定一棵树,每个点有点权,第 \(i\) 个点被删除的代价为 \(w_{p[i]}\times i\) ,问最小代价是多少。

分析

  • 与国王游戏一题类似。

  • 容易发现权值最小的点在其父亲选择后就会立即选择它,可以考虑将其与之父亲合并。

  • 于是问题转化成每个点变得有大小和新的权值,求最小代价。

  • 对于 \(T\) 时刻的没有考虑的数构成的排列,如果 \(i\) 和 \(i-1​\) 交换后更优,则有:

    \[Tw_{i-1}+(T+t_{i-1})w_i>Tw_i+(T+t_i)w_{i-1}
    \]

    化简过后得到:

    \[\frac{t_{i-1}}{w_{i-1}}>\frac{t_i}{w_i}
    \]

  • 这表明每一步的最优解(在当前局面下,一旦可选就立即选择的点)只和剩余序列有关,与之前的选择无关。每次将最最优的点拿去与父亲合并即可。虽然这里有一些不应该进行比较的信息 (比如祖先和儿子),但是并不影响结果。

  • 时间复杂度 \(O(nlogn)\) 。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 5e5 + 7;
int n, ec, nc;
int a[N], par[N], vis[N];
LL ans, t[N], w[N];
struct data {
int u;
LL t, w;
data(){}data(int u, LL t, LL w):u(u), t(t), w(w){}
bool operator <(const data &rhs) const {
if(1ll * t * rhs.w == 1ll * w * rhs.t) return u < rhs.u;
return 1ll * t * rhs.w > 1ll * w * rhs.t;
}
};
set<data>S;
int getpar(int a) {
return par[a] == a ? a : par[a] = getpar(par[a]);
}
int main() {
n = gi();
rep(i, 1, n) {
a[i] = gi();
if(a[i] <= n) {
if(!vis[a[i]]) vis[a[i]] = 1, ++nc;
if(!vis[i]) vis[i] = 1, ++nc;
++ec;
}
}
rep(i, 1, n) w[i] = gi();
if(ec && ec == nc) return puts("-1"), 0;
t[0] = 1;
rep(i, 1, n) {
par[i] = i;
t[i] = 1;
S.insert(data(i, 1, w[i]));
}
while(!S.empty()) {
data now = *S.begin(); S.erase(now);
int u = getpar(now.u), g = getpar(a[u]);
if(g) S.erase(data(g, t[g], w[g]));
ans += t[g] * w[u];
t[g] += t[u];
w[g] += w[u];
par[u] = g;
if(g)
S.insert(data(g, t[g], w[g]));
}
printf("%lld\n", ans);
return 0;
}

[HNOI2018]排列[堆]的更多相关文章

  1. 5289: [Hnoi2018]排列

    5289: [Hnoi2018]排列 链接 分析: 首先将题意转化一下:每个点向a[i]连一条边,构成了一个以0为根节点的树,要求选一个拓扑序,点x是拓扑序中的第i个,那么价值是i*w[x].让价值最 ...

  2. 【BZOJ5289】[HNOI2018]排列(贪心)

    [BZOJ5289][HNOI2018]排列(贪心) 题面 BZOJ 洛谷 题解 这个限制看起来不知道在干什么,其实就是找到所有排列\(p\)中,\(p_k=x\),那么\(k<j\),其中\( ...

  3. bzoj 5289: [Hnoi2018]排列

    Description Solution 首先注意到实际上约束关系构成了一棵树 考虑这个排列 \(p\),编号为 \(a[i]\) 的出现了,\(i\) 才可以出现 那么如果连边 \((a[i],i) ...

  4. [HNOI2018]排列

    Description: 给定 \(n\) 个整数 \(a_1, a_2, \dots, a_n, 0 \le a_i \le n\),以及 \(n\) 个整数 \(w_1, w_2, \dots, ...

  5. loj2509 hnoi2018排列

    题意:对于a数组,求它的一个合法排列的最大权值.合法排列:对于任意j,k,如果a[p[j]]=p[k],那么k<j. 权值:sigma(a[p[i]]*i).n<=50W. 标程: #in ...

  6. BZOJ.5289.[AHOI/HNOI2018]排列(贪心 heap)

    BZOJ LOJ 洛谷 \(Kelin\)写的挺清楚的... 要求如果\(a_{p_j}=p_k\),\(k\lt j\),可以理解为\(k\)要在\(j\)之前选. 那么对于给定的\(a_j=k\) ...

  7. BZOJ5289: [Hnoi2018]排列

    传送门 第一步转化,令 \(q[p[i]]=i\),那么题目变成: 有一些 \(q[a[i]]<q[i]\) 的限制,\(q\) 必须为排列,求 \(max(\sum_{i=1}^{n}w[i] ...

  8. 【比赛】HNOI2018 排列

    这题原题... 这题题面七绕八绕,有点麻烦,反正最后转化就是一棵树,每个点有一个值,要把所有点选完,要求选择一个点必须是它的父亲和祖先已经全部被选了,贡献是这个点的权值乘上它被选择的排名 如果一个点是 ...

  9. [BZOJ5289][HNOI2018]排列(拓扑排序+pb_ds)

    首先确定将所有a[i]向i连边之后会形成一张图,图上每条有向边i->j表示i要在j之前选. 图上的每个拓扑序都对应一种方案(如果有环显然无解),经过一系列推导可以发现贪心策略与合并的块的大小和w ...

随机推荐

  1. Fiddler抓包使用教程-过滤

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72929800 本文出自[赵彦军的博客] Fiddler抓包可以完成我们移动开发者的 ...

  2. (网页)JS和CSS不缓存方法,时间戳

    <link ..... href=".....css?time"+new Date()> <script type="text/javascript&q ...

  3. mybatis学习系列三(部分)

    1 forearch_oracle下批量保存(47) oracle批量插入 不支持values(),(),()方式 1.多个insert放在begin-end里面 begin insert into ...

  4. linux 开机自启动脚本

    在/etc/rc.local文件中添加自启动命令(其中一种方法) 1.案例,就用博主本人之前发的博文 “nginx + flask + uwsgi + centos + python3 搭建web项目 ...

  5. Tensorflow激活函数

    注意: 1.大多情况下使用Relu激活函数这种激活函数计算快,且在梯度下降中不会卡在plateaus(平稳段),对于大的输入,也不会饱和. 2.logistic function和hyperbloic ...

  6. Spring MVC 的工作原理

    引自:https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的工作原理图: SpringMVC流程 1.  用户发送请求至前端控制器Dispat ...

  7. 在LINUX上部署SOFA

    JDK1.6环境变量 vim /etc/profile JAVA_HOME=/usr/local/java/jdk1.6.0_45PATH=$JAVA_HOME/bin:$PATHCLASSPATH= ...

  8. openSUSE搭建OpenVPN

    目录 openSUSE搭建OpenVPN 环境 安装openVPN服务端 安装easy-rsa工具 配置vars文件 创建服务端证书及key 创建客户端证书 疏理证书文件 服务端配置 启动openvp ...

  9. Python 操作 Excel,总有一个模块适合自己

    最近在写性能相关的测试脚本,脚本已经完成,最终怎么体现在报告上,要想让报告看起来漂亮些,我们是先创建一个模板(格式和公式已全部制作好),只需要性能测试完成后往对应的sheet页中填充数据,数据完成后最 ...

  10. P1754 球迷购票问题

    题目背景 盛况空前的足球赛即将举行.球赛门票售票处排起了球迷购票长龙. 按售票处规定,每位购票者限购一张门票,且每张票售价为50元.在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值1 ...