[AT2172] [agc007_e] Shik and Travel
题目链接
AtCoder:https://agc007.contest.atcoder.jp/tasks/agc007_e
洛谷:https://www.luogu.org/problemnew/show/AT2172
Solution
首先由于每条边只能经过两次,所以每次到了\(x\)点就会遍历完\(x\)子树再出来。
考虑二分答案,设当前二分的答案为\(mid\)。
设二元组\((a,b)_x\)表示\(x\)子树下第一次走代价为\(a\)最后一次为\(b\),且中间的过程都\(\leqslant \rm mid\)的一种方案。
那么显然可以得到一个暴力:
我们暴力枚举当前点左儿子和右儿子的二元组,设为\((a,b)_{ls},(c,d)_{rs}\),设左儿子的边权为\(x\),右儿子为\(y\),那么如果满足:\(b+c+x+y\leqslant {\rm mid}\),那么我们可以得到一个新的二元组\((a+x,d+y)_x\)。
考虑如何优化这个玩意,显然对于一个\(a\)只需要一个最小的\(b\),对于\(b\)也同理。
所以显然可以使用\(\rm two \ pointer\)做到每次合并为\(O(sz)\),其中\(sz\)为个数之和。
但是这样可以被卡成\(O(n^2)\),我们加一个启发式合并,每次合并小的,那么每次最多就是\(2|\min(S_{ls},S_{rs})|\)的,总复杂度\(O(n\log^2 n\log \rm ans)\),如果归并排序的话每次处理都是有序的,复杂度可以降为\(O(n\log n \log \rm ans)\)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define ll long long
#define pii pair<int,int >
#define fr first
#define sc second
#define mp make_pair
#define vec vector<pii >
#define pb push_back
#define iter vector <pii > :: iterator
#define for_vec(i,x) for(iter i=x.begin();i!=x.end();i++)
#define _sort(x,y) sort(x.begin(),x.end(),y)
#define I (int)
const int maxn = 3e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
int cmpx(pii x,pii y) {return x.fr<y.fr;}
int cmpy(pii x,pii y) {return x.sc<y.sc;}
int son[maxn][2],v[maxn][2],n,d[maxn],mid,mn[maxn];
vec f[maxn];
void solve(vec &ls,vec &rs,vec &s) {
if(ls.size()>rs.size()) swap(ls,rs); //启发式合并
if(!s.empty()) s.clear();
_sort(ls,cmpy),_sort(rs,cmpx);
mn[0]=rs[0].sc;for(int i=1;i<I rs.size();i++) mn[i]=min(mn[i-1],rs[i].sc);
int p1=0,p2=rs.size()-1;
for(;p1<I ls.size();p1++) {
while(p2>=0&&ls[p1].sc+rs[p2].fr>mid) p2--;
if(~p2) s.pb(mp(ls[p1].fr,mn[p2]));
}
_sort(ls,cmpx),_sort(rs,cmpy);
mn[0]=rs[0].fr;for(int i=1;i<I rs.size();i++) mn[i]=min(mn[i-1],rs[i].fr);
for(p1=0,p2=rs.size()-1;p1<I ls.size();p1++) {
while(p2>=0&&ls[p1].fr+rs[p2].sc>mid) p2--;
if(~p2) s.pb(mp(mn[p2],ls[p1].sc));
}
}
void dfs(int x) {
if(!son[x][0]) return f[x].pb(mp(0,0)),void();
int l=son[x][0],r=son[x][1];dfs(l),dfs(r);
vec &ls=f[l],&rs=f[r];
for_vec(i,ls) i->fr+=v[x][0],i->sc+=v[x][0];
for_vec(i,rs) i->fr+=v[x][1],i->sc+=v[x][1];
solve(ls,rs,f[x]);ls.clear(),rs.clear();
}
signed main() {
read(n);
for(int i=2,x,y;i<=n;i++) read(x),read(y),son[x][d[x]]=i,v[x][d[x]++]=y;
int l=0,r=1e10,ans=1e10;
while(l<=r) {
mid=(l+r)>>1,dfs(1);
if(f[1].empty()) l=mid+1;
else r=mid-1,ans=mid;f[1].clear();
}write(ans);
return 0;
}
[AT2172] [agc007_e] Shik and Travel的更多相关文章
- 【AtCoder Grand Contest 007E】Shik and Travel [Dfs][二分答案]
Shik and Travel Time Limit: 50 Sec Memory Limit: 512 MB Description 给定一棵n个点的树,保证一个点出度为2/0. 遍历一遍,要求每 ...
- AGC007E Shik and Travel 解题报告
AGC007E Shik and Travel 题目大意:\(n\) 个点的二叉树,每个点要么两个儿子,要么没有儿子,每条边有边权. 你从 \(1\) 号节点出发,走到一个叶子节点.然后每一天,你可以 ...
- AT2172 Shik and Travel
题目描述: luogu 题解: 二分+暴力$vector$+$dfs$. 记录下所有可能的子树内合法方案,双指针+归并合并. 代码: #include<vector> #include&l ...
- AtCoder Grand Contest 007 E:Shik and Travel
题目传送门:https://agc007.contest.atcoder.jp/tasks/agc007_e 题目翻译 现在有一个二叉树,除了叶子每个结点都有两个儿子.这个二叉树一共有\(m\)个叶子 ...
- AtCoder AGC007E Shik and Travel (二分、DP、启发式合并)
题目链接 https://atcoder.jp/contests/agc007/tasks/agc007_e 题解 首先有个很朴素的想法是,二分答案\(mid\)后使用可行性DP, 设\(dp[u][ ...
- [AGC007E] Shik and Travel
题目 给定一棵n节点的 以1为根的 满二叉树 (每个非叶子节点恰好有两个儿子)n−1 条边. 第ii条边连接 i+1号点 和 ai, 经过代价为vi设这棵树有m个叶子节点定义一次合法的旅行为:(1) ...
- [atAGC007E]Shik and Travel
二分枚举答案,判定答案是否合法 贪心:每一个叶子只能经过一遍,因此叶子的顺序一定是一个dfs序,即走完一棵子树中的所有叶子才会到子树外 根据这个贪心可以dp,设$f[k][l][r]$表示仅考虑$k$ ...
- 贪心/构造/DP 杂题选做Ⅲ
颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...
- AtCoder Grand Contest 007
AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...
随机推荐
- [WC2010]重建计划 长链剖分
[WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...
- idea 严重: Error configuring application listener of class org.springframework.web.context.Context 后面省略
根本原因:jar文件没有同步发布到自己项目的lib目录中 解决方案:把之前在这个位置的jar文件,put into 到 /WEB-INF/lib 目录下即可
- [flex 布局]——flex教程
简介:2009年,W3C提出了一种新的方案----Flex布局,可以简便.完整.响应式地实现各种页面布局.目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能. Flex布局是什 ...
- javaweb(二十一)——JavaWeb的两种开发模式
一.JSP+JavaBean开发模式 1.1.jsp+javabean开发模式架构 jsp+javabean开发模式的架构图如下图(图1-1)所示
- jmeter逻辑控制器
刚开始学习,只写几种了解的逻辑控制器 1.简单控制器 只用来组合采样器和其他逻辑控制器,不影响jmeter的运行 2.循环控制器 用来循环执行采样器和其他逻辑控制器,例如一个用户发送特定请求多次,即可 ...
- DNS递归查询与迭代查询
注:一般TCP/IP的应用层或者OSI的会话.表示.应用层把数据称为数据或者信息,到了传输层把数据称为报文,到了最底层就是比特流了也就是字节流 DNS递归查询与迭代查询 基础知识 1.域名系统 2 ...
- 音频分析框架pyAudioAnalysis文档
“ pyAudioAnalysis是一个非常好用且强大的音频分析开源工具,能实现音频的特征提取.分类和回归模型的训练和执行,以及其他一些实用的功能.此外,本文档并非直译,也有部分比较简略,可以结合源码 ...
- 17 Tips For Writing An Excellent Email Subject Line
Out of the billions of emails that are sent every day, how can you make sure that yours stands out? ...
- python序列成员资格
可以用做登录操作,判断用户名密码是否正确! 代码示例: database = [ ['], ['], ['], ['] ] username = input("UserName: " ...
- 学习GIT 你只要这一篇(转)
http://blog.csdn.net/afei__/article/details/51476529 安装之后第一步 安装 Git 之后,你要做的第一件事情就是去配置你的名字和邮箱,因为每一次提交 ...