UOJ418. 【集训队作业2018】三角形
题解
考虑激活每个节点时,它的每个儿子都是放满的。
那每一次的操作我们可以用一个二元组来表示\((w_i-\sum w_{son},\sum w_{son})\)。
表示这一次操作完后的增量和这次操作中石子数达到的峰值。
那么一个节点被操作当且仅当它的所有儿子都被操作。
这样很不好处理,所以我们把整个操作序列倒过来,这样限制一个点的只有他的父亲。
那么二元组会变成:\((\sum w_{son}-w_i,\sum w_{son})\),我们还是需要最小化这个序列的历史最值,因为按照这个序列模拟的话是可以还原出它的每一个时刻的。
然后考虑贪心,我们需要对每一个操作求出它的优先度。
对于\(x<0\)的操作,它显然放在前面会更优,如果有多个\(<0\)的操作,\(y\)更小的放在前面。
对于\(x\geq 0\)的操作,我们要让(x,y)优于(dx,dy),那么就有:
\]
前面的常量先不管。
\]
于是我们弄清楚了每个元素的优先度,然后我们求出全局的一个最优序列。
每次找到最优的,如果这个点还没有被父亲激活,那么就和父亲合并。
通过观察我们发现每棵子树的最优序列是全局的子序列,然后我们可以线段树合并求答案。
代码
#include<bits/stdc++.h>
#define N 200002
#define ls tr[cnt].l
#define rs tr[cnt].r
using namespace std;
typedef long long ll;
int f[N],n,id[N],fa[N],T[N],tott,nxt[N];
bool vis[N];
ll w[N],s[N],ans[N],val[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
vector<int>vec[N];
int find(int x){return f[x]=f[x]==x?x:find(f[x]);}
struct node{
ll x,y;
int h,t;
inline node operator +(const node &b)const{return node{x+b.x,max(y,x+b.y),h,b.t};}
inline bool operator <(const node &b)const{
int o1=x>=0,o2=b.x>=0;
if(o1!=o2)return x<b.x;
if(!o1){
if(y!=b.y)return y<b.y;
return h<b.h;
}
if(y-x!=b.y-b.x)return y-x>b.y-b.x;
return h<b.h;
}
};
struct seg{
node x;
int l,r;
}tr[N*23];
node pre[N];
set<node>q;
int merge(int u,int v){
if(!u||!v)return u|v;
tr[u].l=merge(tr[u].l,tr[v].l);
tr[u].r=merge(tr[u].r,tr[v].r);
tr[u].x=tr[tr[u].l].x+tr[tr[u].r].x;
return u;
}
void ins(int &cnt,int l,int r,int x,int id){
cnt=++tott;
if(l==r){
tr[cnt].x=node{val[id],s[id],l,l};
return;
}
int mid=(l+r)>>1;
if(x<=mid)ins(ls,l,mid,x,id);
else ins(rs,mid+1,r,x,id);
tr[cnt].x=tr[ls].x+tr[rs].x;
}
void dfs(int u,int fa){
ins(T[u],1,n,id[u],u);
for(vector<int>::iterator it=vec[u].begin();it!=vec[u].end();++it){
int v=*it;
dfs(v,u);
T[u]=merge(T[u],T[v]);
}
ans[u]=tr[T[u]].x.y+w[u];
}
int main(){
int TT=rd();
n=rd();
for(int i=2;i<=n;++i)fa[i]=rd(),vec[fa[i]].push_back(i);
for(int i=1;i<=n;++i)w[i]=rd(),s[fa[i]]+=w[i],f[i]=i;
for(int i=1;i<=n;++i){
val[i]=s[i]-w[i];
pre[i]=node{val[i],s[i],i,i};
q.insert(pre[i]);
}
vis[0]=1;
int now=0;
while(!q.empty()){
set<node>::iterator it=q.begin();
node x=*it;
q.erase(it);
if(vis[fa[x.h]]){
nxt[now]=x.h;
while(now!=x.t)vis[now]=1,now=nxt[now];
vis[now]=1;
}
else{
int pr=find(fa[x.h]);
q.erase(pre[pr]);
nxt[pre[pr].t]=pre[x.h].h;
pre[pr]=pre[pr]+pre[x.h];
f[find(x.h)]=pr;
q.insert(pre[pr]);
}
}
int cnt=0;
now=0;
for(int i=1;i<=n;++i){
cnt++;
now=nxt[now];
id[now]=i;
}
dfs(1,0);
for(int i=1;i<=n;++i)printf("%lld ",ans[i]);
return 0;
}
UOJ418. 【集训队作业2018】三角形的更多相关文章
- UOJ#418. 【集训队作业2018】三角形
#418. [集训队作业2018]三角形 和三角形没有关系 只要知道儿子放置的顺序,就可以直接模拟了 记录历史最大值 用一个pair(a,b):之后加上a个,期间最大值为增加b个 合并? A1+A2= ...
- UOJ #449. 【集训队作业2018】喂鸽子
UOJ #449. [集训队作业2018]喂鸽子 小Z是养鸽子的人.一天,小Z给鸽子们喂玉米吃.一共有n只鸽子,小Z每秒会等概率选择一只鸽子并给他一粒玉米.一只鸽子饱了当且仅当它吃了的玉米粒数量\(≥ ...
- [UOJ422][集训队作业2018]小Z的礼物——轮廓线DP+min-max容斥
题目链接: [集训队作业2018]小Z的礼物 题目要求的就是最后一个喜欢的物品的期望得到时间. 根据$min-max$容斥可以知道$E(max(S))=\sum\limits_{T\subseteq ...
- 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)
[UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...
- 【UOJ#422】【集训队作业2018】小Z的礼物(min-max容斥,轮廓线dp)
[UOJ#422][集训队作业2018]小Z的礼物(min-max容斥,轮廓线dp) 题面 UOJ 题解 毒瘤xzy,怎么能搬这种题当做WC模拟题QwQ 一开始开错题了,根本就不会做. 后来发现是每次 ...
- 2019.2.25 模拟赛T1【集训队作业2018】小Z的礼物
T1: [集训队作业2018]小Z的礼物 我们发现我们要求的是覆盖所有集合里的元素的期望时间. 设\(t_{i,j}\)表示第一次覆盖第i行第j列的格子的时间,我们要求的是\(max\{ALL\}\) ...
- [集训队作业2018]蜀道难——TopTree+贪心+树链剖分+链分治+树形DP
题目链接: [集训队作业2018]蜀道难 题目大意:给出一棵$n$个节点的树,要求给每个点赋一个$1\sim n$之内的权值使所有点的权值是$1\sim n$的一个排列,定义一条边的权值为两端点权值差 ...
- UOJ#422. 【集训队作业2018】小Z的礼物
#422. [集训队作业2018]小Z的礼物 min-max容斥 转化为每个集合最早被染色的期望时间 如果有x个选择可以染色,那么期望时间就是((n-1)*m+(m-1)*n))/x 但是x会变,中途 ...
- UOJ#428. 【集训队作业2018】普通的计数题
#428. [集训队作业2018]普通的计数题 模型转化好题 所以变成统计有标号合法的树的个数. 合法限制: 1.根标号比子树都大 2.如果儿子全是叶子,数量B中有 3.如果存在一个儿子不是叶子,数量 ...
- uoj450 【集训队作业2018】复读机(生成函数,单位根反演)
uoj450 [集训队作业2018]复读机(生成函数,单位根反演) uoj 题解时间 首先直接搞出单个复读机的生成函数 $ \sum\limits_{ i = 0 }^{ k } [ d | i ] ...
随机推荐
- 第八周课程总结&实验报告六
实验六 Java异常 实验目的 理解异常的基本概念: 掌握异常处理方法及熟悉常见异常的捕获方法. 实验要求 练习捕获异常.声明异常.抛出异常的方法.熟悉try和catch子句的使用. 掌握自定义异常类 ...
- input输入框的的input事件和change事件以及change和blur事件的区别
input输入框的 oninput事件 ,在用户输入的时候触发,只要元素值发生变化就会触发 input输入框的 onchange事件 ,要在输入框失去焦点的时候触发事件,当鼠标在其他地方点击一下才会触 ...
- P1754球迷购票问题
这是一道动态规划题,其实也是个数论题. 有n人拿50,有n人拿100买票,必须让50元的人买,不然无法找零钱,问最多有几种方案可以每一次都买票成功.这个题首先令人想到搜索,但是随即发现dp是正解,于是 ...
- DotNetCore知识栈
#..NET Core提供的特性 1.开源.免费 2.轻量级.跨平台 3.组件化.模块化.IOC+Nuget.中间件 4.高性能 5.统一了MVC和WebAPI编程模型 a) 比如:ASP.NET ...
- linux基本命令vi和vim使用详细介绍
vi使用方法详细介绍 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版 ...
- Kibana 基本操作
es中的索引对应mysql的数据库.类型对应mysql的表.文档对应mysql的记录.映射对应mysql的索引索引:index类型:type映射:mappings 1.创建索引在kibana的Dev ...
- Python 通过dmidecode获取Linux服务器硬件信息
通过 dmidecode 命令可以获取到 Linux 系统的包括 BIOS. CPU.内存等系统的硬件信息,这里使用 python 代码来通过调用 dmidecode 命令来获取 Linux 必要的系 ...
- PyMySQL和MySQLdb的区别
网上很多关于Scrapy存入MySQL的教程,都会发现又这么一个包的引入: import MySQLdb import MySQLdb.cursors 聪明的你或许已经算到,需要安装MySQLdb ...
- 统计学习方法——第四章朴素贝叶斯及c++实现
1.名词解释 贝叶斯定理,自己看书,没啥说的,翻译成人话就是,条件A下的bi出现的概率等于A和bi一起出现的概率除以A出现的概率. 记忆方式就是变后验概率为先验概率,或者说,将条件与结果转换. 先验概 ...
- PAT Basic 1032 挖掘机技术哪家强 (20 分)
为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛.现请你根据比赛结果统计出技术最强的那个学校. 输入格式: 输入在第 1 行给出不超过 1 的正整数 N,即参赛人数.随后 N 行, ...