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,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
随机推荐
- Linux 0.11源码阅读笔记-总结
总结 Linux 0.11主要包含文件管理和进程管理两个部分.进程管理包括内存管理.进程管理.进程间通信模块.文件管理包含磁盘文件系统,打开文件内存数据.磁盘文件系统包括空闲磁盘块管理,文件数据块的管 ...
- python-转换函数使用
输入一个整数和进制,转换成十进制输出 输入格式: 在一行输入整数和进制 输出格式: 在一行十进制输出结果 输入样例: 在这里给出一组输入.例如: 45,8 输出样例: 在这里给出相应的输出.例如: 3 ...
- PAT A1001 A+B Format
Calculate a+b and output the sum in standard format -- that is, the digits must be separated into gr ...
- mixin和composition api
1. 这两个都是实现组件逻辑复用的法宝 2. composition api是vue3的, composition api的出现就是解决mixins的不足之处的 一. mixin 回顾下mixin, ...
- 存储过程 psal emp.sal%type是什么意思
psal emp.sal%type 就是指psal这个变量是引用了表emp中的sal字段的类型.如果emp表中sal的类型变了,psal这个字段的类型也会跟着变化,总之,psal和表emp中sal字段 ...
- 在IntelliJ IDEA配置Tomcat
1,点击Run---EDit Configurations... 2.点击左侧"+"号,找到Tomcat Server---Local(若是没有找到Tomcat Server 可以 ...
- LC-数组-二分查找-704
二分查找 [left, right] 方式 [left, mid -1] [mid + 1, right] int left = 0, right = nums.length - 1; while ( ...
- Ant Design Pro V5 与 IdentityServer 实现 Password 模式的登录
最近处于休息状态,想趁着休息时间,为自己做一个后台. 后端框架选用了 Abp.之前公司使用了一些自研的框架,但由于人力资源有限,后期框架的升级及维护都是比较耗时,这次干脆直接使用Abp,即省心又能快速 ...
- Mybatis结果集映射问题
之前的数据库图简单都是纯小写格式,这一次做项目为了显得正规一些,模拟实际的情况,采用了驼峰命名的规则,这时候就遇到了结果匹配的问题. 之前只要 <select id="select&q ...
- style设置 三个 竖线隔得太近了,这个属性和值 设置让他们分开一点
||| // html letter-spacing: 0.2em; // css