AGC007E Shik and Travel 解题报告
题目大意:\(n\) 个点的二叉树,每个点要么两个儿子,要么没有儿子,每条边有边权。
你从 \(1\) 号节点出发,走到一个叶子节点。然后每一天,你可以从当前点走到另一个叶子。最后回到 \(1\) 号节点,要求到过所有叶子并且每条边经过恰好两次。求一种遍历顺序,使得每相邻两叶子间的边权和的最大值最小。
题解
考虑二分最大值,看是否可行。这个点是一种类似等号转限制的做法。
因此我们只需考虑能否在不经过权值和大于 \(k\) 的叶子间的路径即可。这个怎么做呢?由于我们只关心距离,我们对于每个点可以得到一些数对 \((a,b)\) ,表示当前点子树中可以从距离当前点距离为 \(a\) 的叶子进入,从距离当前点距离为 \(b\) 的叶子退出。并且记 \(S_u\) 为对于 \(u\) 这个点来说形如 \((a,b)\) 的数对集合。
对于没有儿子的点,存在数对 \((0,0)\) 。而对于有儿子的点,由题目限制每条边和每个叶子恰好过两次,可知一个子树内的叶子肯定先互相到达,再离开当前子树,去与最近的子树中的叶子互达。因此我们得到一个非叶子节点的数对,等价于我们将其左右子树的某两个叶子相连接,用左右子树的数对表示,可以得到对于一个子树的数对 \((a,b)\) 和另一个子树的数对 \((c,d)\) ,当 \(b+c+val[u][0]+val[u][1]\le k\) 时(\(val[u][0/1]\) 表示 \(u\) 向左右儿子的边权),这两个数对可以合并,得到数对 \((a+val[u][0],b+val[u][1])\) ,这是默认 \((a,b)\) 为左子树数对,反过来的话 \(val\) 换一下就好。
但是直接暴力合并数对是寄的。我们考虑优化,显然对于两个点对 \((a,b)\) 和 \((c,d)\) ,如果 \(a\le c,b\le d\) ,那么可以知道 \((c,d)\) 是无用的。其次由于我们希望合并出来的数对的两个值都尽量小,且每个数对 \((a,b)\) 都满足 \(a+b\le k\) ,我们对于一个子树中的数对肯定有唯一的一个另一个子树的数对与之对应来得到最小的数对。
我们对于数对按照 \(a\) 从小到大排序,那么由于 \(a+b\le k\) 显然 \(b\) 递减,我们考虑决策单调性来合并即可。
然后我们有决策单调性的话,显然复杂度就是数对总数的,然后由于是一个二叉树,易证复杂度 \(O(n\log n)\) ,总复杂度 \(O(34n\log n)\)。(\(34\) 是二分复杂度)
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define db double
#define filein(a) freopen(#a".in","r",stdin)
#define fileot(a) freopen(#a".out","w",stdout)
#define sky fflush(stdout);
#define gc getchar
#define pc putchar
namespace IO{
inline bool blank(const char &c){
return c==' ' or c=='\n' or c=='\t' or c=='\r' or c==EOF;
}
inline void gs(char *s){
char ch=gc();
while(blank(ch) ) {ch=gc();}
while(!blank(ch) ) {*s++=ch;ch=gc();}
*s=0;
}
inline void gs(std::string &s){
char ch=gc();s+='#';
while(blank(ch) ) {ch=gc();}
while(!blank(ch) ) {s+=ch;ch=gc();}
}
inline void ps(char *s){
while(*s!=0) pc(*s++);
}
inline void ps(const std::string &s){
for(auto it:s)
if(it!='#') pc(it);
}
template<class T>
inline void read(T &s){
s=0;char ch=gc();bool f=0;
while(ch<'0'||'9'<ch) {if(ch=='-') f=1;ch=gc();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=gc();}
if(ch=='.'){
db p=0.1;ch=gc();
while('0'<=ch&&ch<='9') {s=s+p*(ch^48);p*=0.1;ch=gc();}
}
s=f?-s:s;
}
template<class T,class ...A>
inline void read(T &s,A &...a){
read(s);read(a...);
}
};
using IO::read;
using IO::gs;
using IO::ps;
const int N=(1<<17)+3;
int n;
int ch[N][2],val[N][2];
struct node{
int a,b;
};
std::vector<node>S[N],psc;
void dfs(int u,ll k){
S[u].clear();
if(!ch[u][0]){
S[u].push_back({0,0});
return;
}
dfs(ch[u][0],k);
dfs(ch[u][1],k);
int lc=ch[u][0],rc=ch[u][1];
psc.clear();
int j=-1;
for(auto it:S[lc]){
while(j+1<S[rc].size() and S[rc][j+1].a+it.b+val[u][1]+val[u][0]<=k){
++j;
}
if(j>=S[rc].size() ) continue;
if(S[rc][j].a+it.b+val[u][1]+val[u][0]>k) continue;
psc.push_back({it.a+val[u][0],S[rc][j].b+val[u][1]});
}
j=-1;
for(auto it:S[rc]){
while(j+1<S[lc].size() and S[lc][j+1].a+it.b+val[u][1]+val[u][0]<=k){
++j;
}
if(j>=S[lc].size() ) continue;
if(S[lc][j].a+it.b+val[u][1]+val[u][0]>k) continue;
psc.push_back({it.a+val[u][1],S[lc][j].b+val[u][0]});
}
int sz=psc.size();
std::sort(psc.begin(),psc.end(),[](node x,node y){
return x.a<y.a;
});
for(int i=0;i<sz;++i){
if(i!=0){
if(psc[i-1].b<=psc[i].b){
continue;
}
}
S[u].push_back(psc[i]);
}
}
inline bool check(int u,ll k){
dfs(1,k);
return S[1].size();
}
int main(){
filein(a);fileot(a);
read(n);
for(int u=2;u<=n;++u){
int f,w; read(f,w);
if(!ch[f][0]) ch[f][0]=u,val[f][0]=w;
else ch[f][1]=u,val[f][1]=w;
}
ll l=0,r=1ll*(1ll<<17)*(1ll<<17),hf=r;
while(l<=r){
ll mid=(l+r)>>1;
if(check(1,mid) ){
r=mid-1;hf=mid;
}else{
l=mid+1;
}
}
printf("%lld\n",hf);
return 0;
}
AGC007E Shik and Travel 解题报告的更多相关文章
- [JZOJ 5911] [NOIP2018模拟10.18] Travel 解题报告 (期望+树形DP)
题目链接: http://172.16.0.132/senior/#contest/show/2530/1 题目: EZ同学家里非常富有,但又极其的谦虚,说话又好听,是个不可多得的人才. ...
- codeforces 466A. Cheap Travel 解题报告
题目链接:http://codeforces.com/problemset/problem/466/A 题目意思:一个 ride 需要 a 卢布,m 个 ride 需要 b 卢布,这两种方案都可以无限 ...
- [jzoj 5177] [NOIP2017提高组模拟6.28] TRAVEL 解题报告 (二分)
题目链接: https://jzoj.net/senior/#main/show/5177 题目: 题解: 首先选出的泡泡怪一定是连续的一段 L,R 然后 L 一定属于虫洞左边界中的某一个 R 也同样 ...
- [AGC007E] Shik and Travel
题目 给定一棵n节点的 以1为根的 满二叉树 (每个非叶子节点恰好有两个儿子)n−1 条边. 第ii条边连接 i+1号点 和 ai, 经过代价为vi设这棵树有m个叶子节点定义一次合法的旅行为:(1) ...
- AtCoder AGC007E Shik and Travel (二分、DP、启发式合并)
题目链接 https://atcoder.jp/contests/agc007/tasks/agc007_e 题解 首先有个很朴素的想法是,二分答案\(mid\)后使用可行性DP, 设\(dp[u][ ...
- 【LeetCode】Gas Station 解题报告
[LeetCode]Gas Station 解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/gas-station/#/descr ...
- 【LeetCode】743. Network Delay Time 解题报告(Python)
[LeetCode]743. Network Delay Time 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: ht ...
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
随机推荐
- canvas菜鸟基于小程序实现图案在线定制功能
前言 最近收到一个这样的需求,要求做一个基于 vue 和 element-ui 的通用后台框架页,具体要求如下: 要求通用性高,需要在后期四十多个子项目中使用,所以大部分地方都做成可配置的. 要求做成 ...
- 微信小程序 MinUI 组件库系列之 price 价格组件
MinUI 是基于微信小程序自定义组件特性开发而成的一套简洁.易用.高效的组件库,适用场景广,覆盖小程序原生框架.小程序组件化框架等,并且提供了高效的命令行工具.MinUI 组件库包含了很多基础的组件 ...
- ecahrts实现动态刷新(隔几秒重新显示)
代码: <script> var chartDom = document.getElementById('main3'); var myChart = echarts.init(chart ...
- 深入理解nodejs的异步IO与事件模块机制
node为什么要使用异步I/O 异步I/O的技术方案:轮询技术 node的异步I/O nodejs事件环 一.node为什么要使用异步I/O 异步最先诞生于操作系统的底层,在底层系统中,异步通过信号量 ...
- java-GUI编程之AWT组件
AWT中常用组件 基本组件 组件名 功能 Button Button Canvas 用于绘图的画布 Checkbox 复选框组件(也可当做单选框组件使用) CheckboxGroup 用于将多个Che ...
- Windows中Nginx配置nginx.conf不生效解决方法(路径映射)
Windows中Nginx配置nginx.conf不生效解决方法 今天在做Nginx项目的时候,要处理一个路径映射问题, location /evaluate/ { proxy_pass http:/ ...
- C++---初识C++
C和C++的关系 C语言是结构化和模块化的语言, 面向过程. C++是在C语言的基础上, 增加了面向对象的机制, 并对C语言的功能进行了扩充. 变量的定义可以出现在程序中的任何行 提供了标准输入输出流 ...
- JDK1.8.0_181的无限制强度加密策略文件变动(转载)
JDK1.8.0_181的无限制强度加密策略文件变动 原文地址 https://my.oschina.net/my1313677/blog/3109613 作者 葉者 日常记录 2019/09/23 ...
- QT-notepad++仿写
最近小忙,准备学习下FFMPEG 涉及:工具栏使用,QAction,文件基本读写操作 Github地址:https://github.com/wsdassssss/notepad-
- 几种比较经典的波形及其FFT变换(正弦波,三角波,方波和锯齿波)
之前上学时我的信号学得最差了,主要原因还是我高数学得不怎么样.可能是人总敬畏自己最不会的,所以我觉得我学过诸多科目中,数学是最博大精深而最妙的,从最开始的一次函数到反比例函数,二次三次函数和双曲线,椭 ...