[十二省联考2019]春节十二响——长链剖分+堆
题目链接:
[十二省联考2019]春节十二响
可以发现每条链上的所有点都要放在不同的段里,那么最多只需要树的深度这么多段就够了。
因为这样可以保证每条链上的点可以放在不同的段中而且一个点放在这些段中一定会比新开一个段更优。
那么我们先考虑一条链的情况,显然是先将较长的一条链计入答案,然后将另一条链上的点分别与长链上的点合并。
假设长链上的两段分别为$A,B$,其中$A>B$,那么对于另一条链上两个点$C,D$(假设$C>D$)一定是$A$与$C$合并、$B$与$D$合并最优(即大的与大的合并,小的与小的合并)。
可以分情况讨论证明一下:
假设$A>C>B>D$,$max(A,C)+max(B,D)=A+B<max(A,D)+max(B,C)=A+C$
假设$A>C>D>B$,$max(A,C)+max(B,D)=A+D<max(A,D)+max(B,C)=A+C$
假设$C>A>B>D$,$max(A,C)+max(B,D)=C+B<max(A,D)+max(B,C)=A+C$
假设$C>A>D>B$,$max(A,C)+max(B,D)=C+D<max(A,D)+max(B,C)=A+C$
假设$A>B>C>D$,$max(A,C)+max(B,D)=A+B=max(A,D)+max(B,C)=A+B$
假设$C>D>A>B$,$max(A,C)+max(B,D)=C+D=max(A,D)+max(B,C)=C+D$
那么我们只需要将两条链上点的权值都从大到小排序然后依次合并取最大值即可。
现在考虑树的情况,可以发现对于一个节点的所有子树,我们依旧可以按照上述从大到小的顺序将两个子树的最优分段方案合并。
所以只需要对于每个点维护一个大根堆维护这个点的子树分的所有段的权值即可。
因为每次合并的时间复杂度取决于两个堆中较小的那个堆的大小,所以可以将原树长链剖分,每个点继承重儿子的堆然后将其他儿子的堆与重儿子的堆合并,最后将这个点的权值加入堆中即可。
因为每个点被合并一次,所以时间复杂度是$O(nlog_{n})$。
因为每个点继承重儿子的堆,所以实际需要堆的数量是长链数。而且每个点的堆在被合并到其他堆之后就没用了,所以可以类似内存回收一样回收堆。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
priority_queue<int>q[200010];
int num[200010];
int son[200010];
int dep[200010];
int tot;
int head[200010];
int to[200010];
int next[200010];
int n,x;
int val[200010];
int mx[200010];
int cnt;
int sum;
ll ans;
void add(int x,int y)
{next[++tot]=head[x];head[x]=tot;to[tot]=y;
}
void dfs(int x)
{for(int i=head[x];i;i=next[i]){dfs(to[i]);dep[x]=max(dep[x],dep[to[i]]+1);if(dep[to[i]]>=dep[son[x]]){son[x]=to[i];}}
}
void solve(int x)
{ if(son[x]){solve(son[x]);num[x]=num[son[x]];}for(int i=head[x];i;i=next[i]){if(to[i]!=son[x]){solve(to[i]);cnt=0;int a=num[to[i]],b=num[x];while(!q[a].empty()){int x=q[a].top();int y=q[b].top();q[a].pop(),q[b].pop();if(x>y){mx[++cnt]=x;ans-=y;}else{ans-=x;mx[++cnt]=y;}}for(int j=1;j<=cnt;j++){q[b].push(mx[j]);}}}if(!son[x]){num[x]=++sum;}ans+=val[x];q[num[x]].push(val[x]);
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&val[i]);}for(int i=2;i<=n;i++){scanf("%d",&x);add(x,i);}dfs(1);solve(1);printf("%lld",ans);
}
转载于:https://www.cnblogs.com/Khada-Jhin/p/10670571.html
[十二省联考2019]春节十二响——长链剖分+堆相关推荐
- P5290 [十二省联考2019]春节十二响
传送门 考虑一个子树里是怎么划分的,维护划分出来的每个集合的最大值,这个可以用一个 $multiset$ 维护 设 $S[x]$ 表示节点 $x$ 的子树中,最优划分 划分出来的每个块的节点最大值 首 ...
- P5290-[十二省联考2019]春节十二响【贪心,堆】
正题 题目链接:https://www.luogu.org/problemnew/show/P5290 题目大意 将一棵树的所有节点分城若干个组.每个组的价格是这个组中价格最大的点,要求这个组中没有任 ...
- 【十二省联考】春节十二响【贪心】【堆】【启发式合并】
传送门 题意:给一棵nnn个点带点权的树,要求把点分成若干部分,有祖孙关系的点不能在同一部分.求每个部分最大值 的和 的最小值. n≤2×105n \leq 2\times 10^5n≤2×105 由 ...
- P5283-[十二省联考2019]异或粽子【可持久化Trie,堆】
正题 题目链接:https://www.luogu.org/problemnew/show/P5283 题目大意 给定一个序列,求kkk个不同的的[l..r][l..r][l..r]的区间异或值的和最 ...
- 十二省联考 2019 题解
[十二省联考2019]异或粽子 首先异或转前缀和,类似超级钢琴,将三元组 ( l , r , p ) (l,r,p) (l,r,p) 插入堆,表示 s u m [ p ] sum[p] sum[p] ...
- 【BZOJ5498】[十二省联考2019]皮配(动态规划)
[BZOJ5498][十二省联考2019]皮配(动态规划) 题面 BZOJ 洛谷 题解 先考虑暴力\(dp\),设\(f[i][j][k]\)表示前\(i\)所学校,有\(j\)人在某个阵营,有\(k ...
- 【十二省联考2019】春节十二响
题面 https://www.luogu.org/problem/P5290 题解 真的是我傻逼,十二省联考$day2$至今还是我的噩梦.$day1$起码一直在调可持久化$trie$树,$day2$真 ...
- 「十二省联考 2019」皮配——dp
题目 [题目描述] #### 题目背景 一年一度的综艺节目<中国好码农>又开始了.本季度,好码农由 Yazid.Zayid.小 R.大 R 四位梦想导师坐镇,他们都将组建自己的梦想战队,并 ...
- 十二省联考2019酱油记
在中考前去省选玩一趟. Day -1 对于一个还没有学会所有省选内容的初三Oier来说,这一趟真的是去打酱油的啊.但还是要认真复习. 最近几天在字符串的路上越走越远-晚上才开始复习图论.还有一大堆没有 ...
最新文章
- SharePoint 2013 配置HTTPS(SSL)
- c++ ifstream 文件不结束_C++核心编程 第十二节 文件操作
- tasker使用手册_如何开始使用Tasker调整Android手机
- 面试分享:那些年我经历过的一些面试,以及得到的一些面试心得!
- C语言---关于关键字const与static的简单理解
- linux下安装Telnet服务器
- 几种常用网络传输协议
- 冰点还原离线激活_冰点还原密钥,小编教你如何激活冰点还原
- python对话框打开文件_python打开文件对话框
- access有效性规则不为空值_access窗体文本框有效性规则中输入is not null无效
- codeforces949D Curfew
- C# 学习笔记04-15
- CF1592B Hemose Shopping
- linux shell -常用脚本
- 招商银行笔试题之跳格子游戏
- Bootstrap 排版缩写词
- 传奇服务器都有哪些文件,传奇服务端每个文件夹的含义
- word 2010打不开03格式文档解决办法
- 【已解决】群晖6.x套件中心找不到花生壳套件
- 小白经济学(一)—经济学是什么