Poj2054 color a tree && [HNOI/AHOI2018]排列
https://zybuluo.com/ysner/note/1120723
题面
原题
某省选强化题
大致意思是给你一颗树,选父亲后才能选儿子。
每个点对答案的贡献为你在第几次选这个点 × 该点权值
问取完所有点最小答案是多少。
- 对于\(60pts\) \(n\leq1000\)
- 对于\(100pts\) \(n\leq500000\)
解析
贪心没学好,_ _ _ _ _(自己yy)
答案要求的其实是个选取序列。。。
我们可以发现,要保证答案最优性,最大点取的时间越小越好。
又可以发现,只要最大点父亲已选,下一个点选最大点肯定最优。
这时我们确定了一部分顺序,可以想,为什么不能把已确定的、前后相邻选的两点合并起来呢?
现在问题就是如何在几个大点中作抉择了。
可以发现,此时如果大点\(a[i]/t[i]\)越大(\(a[i]\)是权值和,\(t[i]\)是时间和),就是性价比越高,先选越优。
对于\(n\leq1000\)
显然\(a[i]/t[i]\)看起来有点鬼
我们要用更有区分度的比较方式
如果\(a[i]/t[i]>a[j]/t[j]\)
那么\(a[i]*t[j]>a[j]*t[i]\)
于是每次按着贪心策略合并点,对答案的贡献为其父亲选完所用时间×点权值,再把新点与被合并点的儿子相连即可。
int main()
{
while(233)
{
memset(h,-1,sizeof(h));ans=0;cnt=0;
n=gi();r=gi();
if(!n&&!r) break;t[0]=1;
fp(i,1,n) a[i]=gi(),t[i]=1;
fp(i,1,n-1)
{
re int u=gi(),v=gi();
add(u,v);f[v]=u;
}
f[r]=0;
re int res=n;
while(res--)
{
re int mx=1;
fp(i,2,n)
if(a[i]*t[mx]>a[mx]*t[i]) mx=i;
ans+=a[mx]*t[f[mx]];
a[f[mx]]+=a[mx];t[f[mx]]+=t[mx];
for(re int i=h[mx];i+1;i=e[i].nxt)
{
re int v=e[i].to;
f[v]=f[mx];
add(f[mx],v);
}
a[mx]=-1;
}
printf("%lld\n",ans);
}
return 0;
}
Update:发现一个很蛋疼的问题:用并查集就不用新建边了。
对于\(n\leq500000\)
裸贪心是\(O(n^2)\)的。
我们需要一个能马上提供最大点的堆来降低复杂度。
struct node{int u,sz;ll w;bool operator < (const node &o) const {return w*o.sz>o.w*sz;}};
priority_queue<node> Q;
il void dfs(re int u)
{
vis[u]=1;++tim;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(vis[v]) {puts("-1");exit(0);}
dfs(v);
}
}
il int find(re int x){return x==F[x]?x:F[x]=find(F[x]);}
int main()
{
memset(h,-1,sizeof(h));ans=0;
n=gi();
fp(i,1,n) f[i]=gi(),add(f[i],i);
dfs(0);if(tim<=n) return puts("-1"),0;
fp(i,0,n) F[i]=i,sz[i]=1;
fp(i,1,n) w[i]=gi(),Q.push((node){i,1,w[i]});
re int u,p;
while(!Q.empty())
{
node s=Q.top();Q.pop();u=find(s.u);
if(sz[u]^s.sz) continue;//扔掉不符合当前情况的决策
F[u]=p=find(f[u]);
ans+=w[u]*sz[p];
w[p]+=w[u];sz[p]+=sz[u];
if(p) Q.push((node){p,sz[p],w[p]});
}
printf("%lld\n",ans);
return 0;
}
Poj2054 color a tree && [HNOI/AHOI2018]排列的更多相关文章
- 【LG4437】[HNOI/AHOI2018]排列
[LG4437][HNOI/AHOI2018]排列 题面 洛谷 题解 题面里这个毒瘤的东西我们转化一下: 对于\(\forall k,j\),若\(p_k=a_{p_j}\),则\(k<j\). ...
- [HNOI/AHOI2018]排列 贪心
题面 题解: 把题面的限制换成中文: 如果排在第k位的下标 = 排在第j位的值 ,那么k < j 换一个描述方式: 一个值为x的数要排在第x个数后面. 再换一个描述方式: \(fa[i] = a ...
- [HNOI/AHOI2018]排列
[Luogu4437] 如果\(a[i]=j\)则序列\(p[]\)中\(j\)必须排在\(i\)前面,如果\(j\)不在范围内则不管,求一个式子\(\sum_{i=1}^n iw_{p[i]}\)的 ...
- 洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)
题面传送门 开始 WA ycx 的遗产(bushi 首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_ ...
- [POJ2054]Color a Tree (并查集+贪心)
POJ终于修好啦 题意 和UVA1205是同一题,在洛谷上是紫题 有一棵树,需要给其所有节点染色,每个点染色所需的时间是一样的都是11.给每个点染色,还有一个开销“当前时间×ci×ci”,cici是每 ...
- poj2054 Color a Tree
神题.这题是巨毒瘤... 自己写真可谓是: 排空驭气奔如电,上天入地求之遍 上穷碧落下黄泉,两处茫茫皆不见 由于我们知道:不是树形时,不停选值最大的节点可以得到最小代价. 那么我们就能想出一个错误的贪 ...
- BZOJ5289 HNOI/AHOI2018排列(贪心+堆)
题面描述的相当绕,其实就是如果ai=j,重排后ai要在aj之后.同时每个ai有附属属性wi,要求最大化重排后的Σiwi. 容易发现这事实上构成一张图,即由j向i连边.由于每个点入度为1或0,该图是基环 ...
- 【洛谷 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 考虑 ...
随机推荐
- Apache添加到windows服务和移除Apache的windows服务
Apache添加到windows服务和移除Apache的windows服务 Apache免安装版将其添加到Windows服务中: 打开cmd控制台,在上面输入"你的Apache安装目录\bi ...
- Java基础——工具类
一Java 常用类 Object Object类是所有类.数组.枚举类的父类.位于Java.lang包.也就是说,Java允许把任意类型的对象赋给Object类型的变量. Object类的常用方法 1 ...
- java基础——String的常用方法
java中String的常用方法 1.length() 字符串的长度 例:char chars[]={'a','b'.'c'}; String s=new String(chars); i nt le ...
- Go:内置函数
一.内置函数 close // 主要用来关闭channel len // 用来求长度,比如string.array.slice.map.channel new // 用来分配内存,主要用来分配值类型, ...
- Redis多实例配置以及主从同步
一.多实例配置 1.准备俩配置文件,开两个就准备两个 redis-6380.conf redis-6381.conf 2.分别写入配置信息(这里简化了配置) # 运行在6380端口 bind 172. ...
- 微信小程序火爆,谁能在微信小程序赚取第一桶金?
2016年末,最火的话题:微信小程序.身边好多朋友蠢蠢欲动的想要借微信小程序创业,春节期间整理思绪,我们就简单说说微信的小程序可能会让哪些人赚钱: 1,微信小程序培训,能够快速赚钱 做培训的肯定首先赚 ...
- 设置NODE_ENV=test环境变量
之前开发时因为有内网测试环境和外网测试环境,再部署打包时总是切换两个域名,比较麻烦,所以最好能设置一个环境变量,来控制两个域名,于是做了如下配置: "scripts": { &qu ...
- (13)Corner Detection角点检测
import cv2 import numpy as np img=cv2.imread('opencv-corner-detection-sample.jpg') gray = cv2.cvtCol ...
- java多线程编程核心技术(三)--线程间通信
1.等待/通知机制 1.wait()方法:使当前执行代码的线程进行等待.wait()方法是Object类的方法,该方法将当前线程放入“预执行队列”中,并在wait()所处的代码行处停止执行.只到被唤起 ...
- Linux下汇编语言学习笔记35 ---
这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...