题意

给定一棵树,每个点有点权,第 \(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. python网络编程:socket、服务端、客户端

    本文内容: socket介绍 TCP: 服务端 客户端 UDP: 服务端 客户端 首发时间:2018-02-08 01:14 修改: 2018-03-20 :重置了布局,增加了UDP 什么是socke ...

  2. Ubuntu16下配置支持Windows访问的samba共享

    一.安装Ubuntu samba服务器 $ sudo apt-get install samba $ sudo apt-get install smbclient # Linux客户端测试用 二.创建 ...

  3. LeetCode题解之Binary Tree Paths

    1.题目描述 2.分析 使用递归. 3.代码 vector<string> ans; vector<string> binaryTreePaths(TreeNode* root ...

  4. CSS| 框模型-border

    CSS 边框属性

  5. if条件简单语法

    if语句是实际工作中最重要最常用的语句. if条件语法: 单分支结构 if [ 条件 ] then 指令 fi 或 if [ 条件 ]:then 指令 fi if 单分支条件中文编程形象语法: 如果 ...

  6. 【待完成】[MapReduce_9] MapReduce 的 Shuffle 机制

    0. 说明 待补充...

  7. Python基础知识:if语句

    1.模拟网站确保用户名是否重复的方式,无视大小写,用到函数lower() #检查用户名是否重复 current_users=['admin','alex','lebran','kaobi','Jame ...

  8. January 02nd, 2018 Week 01st Tuesday

    I dream my painting, and then I paint my dream. 我梦见我的画,然后我画我的梦. It was a long time after I had a goo ...

  9. JAVA基础-栈与堆,static、final修饰符、内部类和Java内存分配

    Java栈与堆 堆:顺序随意 栈:后进先出(Last-in/First-Out). Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和mu ...

  10. 用requests爬取一个招聘网站

    import requestsimport re session = requests.session()第一步:访问登陆页,拿到X_Anti_Forge_Token,X_Anti_Forge_Cod ...