AtCoder AGC007E Shik and Travel (二分、DP、启发式合并)
题目链接
https://atcoder.jp/contests/agc007/tasks/agc007_e
题解
首先有个很朴素的想法是,二分答案\(mid\)后使用可行性DP, 设\(dp[u][x][y]\)表示\(u\)子树内是否可以找到一条路径,在经过第一个叶子前路程是\(x\), 经过最后一个叶子前路程是\(y\).
这个DP显然做了很多无用功,比如我们发现完全可以只记录true的状态\((x,y)\),进一步发现如果合法状态\((x,y)\)存在另一合法状态\((x',y')\)满足\(x'\le x,y'<\le y\), 那么就没有必要存储\((x,y)\)了。于是我们按\(x\)递增的顺序存储\((x,y)\),那么\(y\)一定是递减的。
这样简化之后,我们发现一个神奇的性质: 设\(S_u\)为\(u\)记录的集合,\(i\)和\(j\)为儿子,那么\(|S_u|\le 2\min(|S_i|,|S_j|)\). 这是因为\(x\)和\(y\)的取值都各有\(\min(|S_i|,|S_j|)\)种。
考虑合并的过程: 假设路径的开头在\(i\)内,那么我们需要找到\((x_1,y_1)\in S_i, (x_2,y_2)\in S_j\), 若\(y_1+v_i+v_j+x_2\le mid\), 则把\((x_1+v_i,y_2+w_j)\)加入\(S_u\). 这个显然可以用双指针优化. 路径的开头在\(j\)内也同理。
类似启发式合并可分析复杂度。算上二分总复杂度\(O(n\log^2n)\).
代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
#include<vector>
#define llong long long
#define pll pair<llong,llong>
#define mkpr make_pair
using namespace std;
const int N = 1<<17;
int son[N+3][2];
llong w[N+3];
vector<pll> dp[N+3];
vector<pll> aux1,aux2;
int n,en;
llong mid;
void dfs(int u)
{
// printf("dfs %d\n",u);
dp[u].clear(); int ls = son[u][0],rs = son[u][1];
if(!ls)
{
dp[u].push_back(mkpr(0ll,0ll));
return;
}
dfs(ls); dfs(rs);
aux1.clear(); aux2.clear();
if(dp[rs].size())
{
int j = 0;
for(int i=0; i<dp[ls].size(); i++)
{
while(j<dp[rs].size()-1 && dp[rs][j+1].first+dp[ls][i].second+w[ls]+w[rs]<=mid) {j++;}
if(j<dp[rs].size() && dp[rs][j].first+dp[ls][i].second+w[ls]+w[rs]<=mid) {aux1.push_back(mkpr(dp[ls][i].first+w[ls],dp[rs][j].second+w[rs]));}
}
}
if(dp[ls].size())
{
int j = 0;
for(int i=0; i<dp[rs].size(); i++)
{
while(j<dp[ls].size()-1 && dp[ls][j+1].first+dp[rs][i].second+w[ls]+w[rs]<=mid) {j++;}
if(j<dp[ls].size() && dp[ls][j].first+dp[rs][i].second+w[ls]+w[rs]<=mid) {aux2.push_back(mkpr(dp[rs][i].first+w[rs],dp[ls][j].second+w[ls]));}
}
}
int j = 0,k = 0; llong cur = 1ll<<34;
while(j<aux1.size() || k<aux2.size())
{
if(k==aux2.size() || (j<aux1.size() && aux1[j].first<=aux2[k].first))
{
if(aux1[j].second<cur) {dp[u].push_back(aux1[j]); cur = aux1[j].second;}
j++;
}
else
{
if(aux2[k].second<cur) {dp[u].push_back(aux2[k]); cur = aux2[k].second;}
k++;
}
}
}
bool check()
{
dfs(1);
if(dp[1].size()) {return true;}
else {return false;}
}
int main()
{
scanf("%d",&n);
for(int i=2; i<=n; i++)
{
int u; llong x; scanf("%d%lld",&u,&x);
w[i] = x; if(son[u][0]) son[u][1] = i; else son[u][0] = i;
}
llong left = 0ll,right = 1ll<<34;
while(left<right)
{
mid = left+((right-left)>>1)
// printf("mid=%lld\n",mid);
bool ok = check();
if(ok) {right = mid;}
else {left = mid+1;}
}
printf("%lld\n",right);
return 0;
}
AtCoder AGC007E Shik and Travel (二分、DP、启发式合并)的更多相关文章
- AGC007E Shik and Travel 解题报告
AGC007E Shik and Travel 题目大意:\(n\) 个点的二叉树,每个点要么两个儿子,要么没有儿子,每条边有边权. 你从 \(1\) 号节点出发,走到一个叶子节点.然后每一天,你可以 ...
- ARC 086 E - Smuggling Marbles(dp + 启发式合并)
题意 Sunke 有一棵 \(N + 1\) 个点的树,其中 \(0\) 为根,每个点上有 \(0\) 或 \(1\) 个石子, Sunke 会不停的进行如下操作直至整棵树没有石子 : 把 \(0\) ...
- BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】
题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启 ...
- [AGC007E] Shik and Travel
题目 给定一棵n节点的 以1为根的 满二叉树 (每个非叶子节点恰好有两个儿子)n−1 条边. 第ii条边连接 i+1号点 和 ai, 经过代价为vi设这棵树有m个叶子节点定义一次合法的旅行为:(1) ...
- 【AtCoder Grand Contest 007E】Shik and Travel [Dfs][二分答案]
Shik and Travel Time Limit: 50 Sec Memory Limit: 512 MB Description 给定一棵n个点的树,保证一个点出度为2/0. 遍历一遍,要求每 ...
- [AT2172] [agc007_e] Shik and Travel
题目链接 AtCoder:https://agc007.contest.atcoder.jp/tasks/agc007_e 洛谷:https://www.luogu.org/problemnew/sh ...
- P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并
LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...
- [多校 NOIP 联合模拟 20201130 T4] ZZH 的旅行(斜率优化dp,启发式合并,平衡树)
题面 题目背景 因为出题人天天被 ZZH(Zou ZHen) 吊打,所以这场比赛的题目中出现了 ZZH . 简要题面 数据范围 题解 (笔者写两个log的平衡树和启发式合并卡过的,不足为奇) 首先,很 ...
- 二分+DP HDU 3433 A Task Process
HDU 3433 A Task Process Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
随机推荐
- 树莓派安装SSH
1. 安装ssh sudo apt-get install openssh-server 2. 检查树莓派SSH服务是否开启 ps -e|grep ssh 3. SSH服务开启 sudo /etc/i ...
- 【原创】大数据基础之Kudu(6)kudu tserver内存占用统计分析
kudu tserver占用内存过高后会拒绝部分写请求,日志如下: 19/06/01 13:34:12 INFO AsyncKuduClient: Invalidating location 34b1 ...
- 非常有用的pointer-events属性
介绍 pointer-events是css3的一个属性,指定在什么情况下元素可以成为鼠标事件的target(包括鼠标的样式) 属性值 pointer-events属性有很多值,但是对于浏览器来说,只有 ...
- (三)创建基于maven的javaFX+springboot项目创建
创建基于maven的javaFx+springboot项目有两种方式,第一种为通过非编码的方式来设计UI集成springboot:第二种为分离用户界面(UI)和后端逻辑集成springboot,其中用 ...
- 帝国cms 权限操作
<? if ($classid==5 || $classid==6 || $classid==7 || $classid==8 || $classid==9 || $classid==10 || ...
- Java学习笔记【十三、多线程编程】
概念 Java 给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别的形式,但多线 ...
- odoo 权限文件说明
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink (权限的定义)access_book_user ...
- 查看电脑物理地址(MAC)方法
首先打开电脑,按ctrl+R键,将会出现以下界面 然后直接点击确认即可,会出现管理员界面,如下 我们现在有两种查看MAC地址的方法: 方法一:.直接输入ipconfig/all(或者输入ipconfi ...
- LoadRunner(1)
性能测试:HP LoadRunner11 一.初步概念: 1.功能测试:测试产品的功能是否满足功能需求. 如:ATM取款(在线取款)是否成功或转账操作是否成功 -- 一个用户 2.性能测试:测试产品的 ...
- Android异常与性能优化相关面试问题-内存泄漏面试问题讲解
Java内存泄漏基础知识: Java的内存的分配策略 a.静态存储区:也叫方法区,主要是存放一些静态数据及全局变量等,在程序编译时就已经分配好了,并且在静态存储区中存放的变量在整个程序运行期间都存在. ...