【AtCoder Grand Contest 007E】Shik and Travel [Dfs][二分答案]
Shik and Travel
Time Limit: 50 Sec Memory Limit: 512 MB
Description
给定一棵n个点的树,保证一个点出度为2/0。
遍历一遍,要求每条边被经过两次,第一次从根出发,最后一次到根结束,在叶子节点之间移动。
移动一次的费用为路径上的边权之和,第一次和最后一次免费,移动的最大费用 最小可以是多少。
Input
第一行一个n,表示点数。
之后两个数x, y,若在第 i 行,表示 i+1 -> x 有一条权值为 y 的边。
Output
输出一个数表示答案。
Sample Input
7
1 1
1 1
2 1
2 1
3 1
3 1
Sample Output
4
HINT
2 < n < 131,072
0 ≤ y ≤ 131,072
Solution
问题的本质就是:求一个叶子节点排列,按照排列顺序走,使得两两距离<=K。
因为第一天和最后一天不花费,可以第一天从根走到一个叶子,最后一天从某一叶子走回根。
我们首先二分答案。
对于子树u维护二元组(a, b),表示存在方案可以 从 与u距离为a的点 出发 然后走到 与u距离为b的点,并且遍历了u中的所有叶子节点。
用个vector存一下即可。显然,若a升序,则b要降序,否则是无用状态。
运用Dfs,从叶子节点往上推。我们现在考虑如何合并子树u、v的(a, b)。给一棵子树编号(a1, b1),另一棵为(a2, b2)。
我们新二元组的走法应该是 a1->b1, b1->a2, a2->b2 的,
只要保证 b1->a2 这一条路径 权值和<=K 即可合并成(a1 + (u->fa), b2 + (v->fa))。
显然用(a1, b1)去合并只有一个有用状态:满足b1 + a2 + (u->fa) + (v->fa)<=K,a2尽量大,因为这样b2会尽量小。
枚举size较小的一边,二分一下另外一边即可。
若推到根存在一组二元组即可行。
Code
- #include<iostream>
- #include<string>
- #include<algorithm>
- #include<cstdio>
- #include<cstring>
- #include<cstdlib>
- #include<cmath>
- #include<vector>
- using namespace std;
- typedef long long s64;
- const int ONE = ;
- const s64 INF = 1e18;
- #define next nxt
- int get()
- {
- int res = , Q = ; char c;
- while( (c = getchar()) < || c > )
- if(c == '-') Q = -;
- if(Q) res = c - ;
- while( (c = getchar()) >= && c <= )
- res = res * + c - ;
- return res * Q;
- }
- struct power
- {
- s64 a, b;
- bool operator <(power A) const
- {
- if(A.a != a) return a < A.a;
- return b < A.b;
- }
- };
- vector <power> A[ONE], R;
- int n;
- int x, y;
- s64 l, r, K;
- int next[ONE], first[ONE], go[ONE], w[ONE], tot;
- int size[ONE], fat[ONE];
- void Add(int u, int v, int z)
- {
- next[++tot] = first[u], first[u] = tot, go[tot] = v, w[tot] = z;
- next[++tot] = first[v], first[v] = tot, go[tot] = u, w[tot] = z;
- }
- int dist[ONE];
- int len_x, len_y;
- s64 a1, b1, a2, b2;
- int Find()
- {
- if(len_y == ) return len_y;
- int l = , r = len_y - ;
- while(l < r - )
- {
- int mid = l + r >> ;
- a2 = A[y][mid].a, b2 = A[y][mid].b;
- if(b1 + a2 + dist[x] + dist[y] <= K) l = mid;
- else r = mid;
- }
- a2 = A[y][r].a, b2 = A[y][r].b; if(b1 + a2 + dist[x] + dist[y] <= K) return r;
- a2 = A[y][l].a, b2 = A[y][l].b; if(b1 + a2 + dist[x] + dist[y] <= K) return l;
- return len_y;
- }
- void Update(int u)
- {
- x = , y = ;
- for(int e = first[u]; e; e = next[e])
- if(go[e] != fat[u])
- if(!x) x = go[e]; else y = go[e];
- if(size[x] > size[y]) swap(x, y);
- len_x = A[x].size(), len_y = A[y].size();
- R.clear();
- for(int i = ; i < len_x; i++)
- {
- a1 = A[x][i].a, b1 = A[x][i].b;
- if(Find() >= len_y) continue;
- R.push_back((power){a1 + dist[x], b2 + dist[y]});
- R.push_back((power){b2 + dist[y], a1 + dist[x]});
- }
- sort(R.begin(), R.end());
- int len = R.size();
- s64 maxx = INF;
- for(int i = ; i < len; i++)
- if(R[i].b < maxx)
- A[u].push_back(R[i]), maxx = R[i].b;
- }
- void Dfs(int u, int father)
- {
- size[u] = ;
- int pd = ;
- for(int e = first[u]; e; e = next[e])
- {
- int v = go[e];
- if(v == father) continue;
- fat[v] = u, dist[v] = w[e];
- Dfs(v, u);
- size[u] += size[v], pd++;
- if(pd == ) Update(u);
- }
- if(!pd) A[u].push_back((power){, });
- }
- int Check()
- {
- for(int i = ; i <= n; i++)
- A[i].clear();
- Dfs(, );
- return A[].size() > ;
- }
- int main()
- {
- n = get();
- for(int i = ; i <= n; i++)
- {
- x = get(), y = get();
- Add(i, x, y), r += y;
- }
- while(l < r - )
- {
- K = l + r >> ;
- if(Check()) r = K;
- else l = K;
- }
- K = l;
- if(Check()) printf("%lld", l);
- else printf("%lld", r);
- }
- 广泛的交换
【AtCoder Grand Contest 007E】Shik and Travel [Dfs][二分答案]的更多相关文章
- AtCoder Grand Contest 007
AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
- AtCoder Grand Contest 031 简要题解
AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...
- AtCoder Grand Contest 010
AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
- AtCoder Grand Contest 009
AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...
- AtCoder Grand Contest 006
AtCoder Grand Contest 006 吐槽 这套题要改个名字,叫神仙结论题大赛 A - Prefix and Suffix 翻译 给定两个串,求满足前缀是\(S\),后缀是\(T\),并 ...
- AtCoder Grand Contest 005
AtCoder Grand Contest 005 A - STring 翻译 给定一个只包含\(ST\)的字符串,如果出现了连续的\(ST\),就把他删去,然后所有位置前移.问最后剩下的串长. 题解 ...
- AtCoder Grand Contest 004
AtCoder Grand Contest 004 A - Divide a Cuboid 翻译 给定一个\(A*B*C\)的立方体,现在要把它分成两个立方体,求出他们的最小体积差. 题解 如果有一条 ...
- AtCoder Grand Contest 014
AtCoder Grand Contest 014 A - Cookie Exchanges 有三个人,分别有\(A,B,C\)块饼干,每次每个人都会把自己的饼干分成相等的两份然后给其他两个人.当其中 ...
随机推荐
- 父元素如果为none,子元素也是看不到的
1.最近遇到一个问题,就是获取一个子元素的offsetwidth 的值总是为0 .原因是因为把父元素给设置成none了. 2.给元素赋值宽高 div.style.width=330+'px' 要加上p ...
- beta——5
一.提供当天站立式会议照片一张: 二. 每个人的工作 (有work item 的ID) (1) 昨天已完成的工作: 对用户功能的添加. (2) 今天计划完成的工作: web发布 (3) 工作中遇到的困 ...
- [转帖] CentOS7 与 CentOS6的对比
来源网站: http://blog.51cto.com/fengery/1901349 centos6.x_centos7.x差异改进明细 感谢原作者 centos官方帮助文档:https://wik ...
- 关闭SSD(固态硬盘)节能功能 提搞SSD性能
此方法可以缓解比如QQ聊天时能明显感觉到打字过程不连续,0.1s左右的间歇停顿,操作系统并不会锁死,系统突然停止响应,硬盘灯狂闪,鼠标指针成为圆圈,点什么都没反应,这种状况可能会持续1-2分钟, ...
- Two Sum III - Data structure design
Design and implement a TwoSum class. It should support the following operations: add and find. add - ...
- BZOJ3309 DZY Loves Math(莫比乌斯反演+线性筛)
一通正常的莫比乌斯反演后,我们只需要求出g(n)=Σf(d)*μ(n/d)的前缀和就好了. 考虑怎么求g(n).当然是打表啊.设n=∏piai,n/d=∏pibi .显然若存在bi>1则这个d没 ...
- 01 Spring Boot 的简单配置和使用
Spring Boot 简介 使用 Spring Boot 可以让我们快速创建一个基于 Spring 的项目,而让这个 Spring 项目跑起来我们只需要很少的配置就可以了. 创建 Spring Bo ...
- vyos 基础配置
vyos 基础配置 http://www.lowefamily.com.au/2015/11/29/using-a-vyos-router-with-hyper-v/1/http://thomasvo ...
- oracle +plsql装完省略号不能点
1.如图 2.复制 TNS 服务名 3.复制到 登录框的 Database ,输入用户名密码,点OK..可以进去了,省略号变成可点击状态
- 学习Spring Boot:(二)启动原理
前言 主要了解前面的程序入口 @@SpringBootApplication 这个注解的结构. 正文 参考<SpringBoot揭秘 快速构建微服务体系>第三章的学习,总结下. Sprin ...