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,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
随机推荐
- 【Android开发】Android 颜色透明度换算
透明度 透明度分为256阶(0-255),计算机上用16进制表示为(00-ff). 透明就是0阶,不透明就是255阶,如果50%透明就是127阶(256的一半当然是128,但因为是从0开始,所以实际上 ...
- DOM节点详解
@ 目录 学习总结 1. 什么是 DOM 2. HTMLDOM 3. 元素获取 元素获取方式: 元素节点的属性操作 4. Node 对象的属性和方法 常用属性 常用方法 5. 事件处理 事件驱动编程 ...
- zabbix 服务器500错误,解决故障。
ZABBIX 500错误,查看apache错误日志,index.php 32 line.写着语法错误!!! 到路径下打开/var/www/html/zabbix/index.php文件,定位32行,可 ...
- centOS一次性更新所有依赖库
CentOS中使用yum一次性更新安装依赖库 [tom@localhost /]# sudo -s [root@localhost /]# LANG=C [root@localhost /]# yum ...
- 一. 为什么要用SpringMVC框架
以前是怎么做项目的.CoreServlet,起到一个中心处理器作用.所有的请求到服务器,服务器给CoreServlet,在里面处理所有表的增删改查,跳转也在里面做.以前做部门就是 DepServlet ...
- matplotlib---设置坐标轴
import matplotlib.pyplot as plt import numpy as np # 一维数组, 元素为从-3到3之间均匀地产生50个点 x = np.linspace(-3, 3 ...
- Svelte3聊天室|svelte+svelteKit仿微信聊天实例|svelte.js开发App
基于svelte3.x+svelteKit构建仿微信App聊天应用svelte-chatroom. svelte-chatroom 基于svelte.js+svelteKit+mescroll.js+ ...
- Lumia一键刷稳定版 Win10 arm 及其报错处理
前言 之前我发了一篇Lumia1520 刷Win10 arm双系统的文章,不过后来发现那个方法对小白来说太不友好,且系统也不稳定,所以我找到了更好的方法 刷机 我们可以利用刷机迷进行刷机,支持一键刷机 ...
- [翻译] 使用 TensorFlow 进行分布式训练
本文以两篇官方文档为基础来学习TensorFlow如何进行分布式训练,借此进入Strategy世界.
- vue3 操作修改数据
vue2.x改变数据: <template> <div class="v2"> 这是数据展示: <div v-for=" ...