UVALive 7148 LRIP(树的分治+STL)(2014 Asia Shanghai Regional Contest)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=648&page=show_problem&problem=5160
There is a tree with N nodes, and every node has a weighted value. A RIP (restricted increasing path)
is a directed path with all nodes’ weighted values not decreasing and the difference between the max
weighted value and the min weighted value is not larger than D. Find the length of longest restricted
increasing path (LRIP).
A path in a tree is a finite or in finite sequence of edges which connect a sequence of vertices which
are all distinct from one another. A directed path is again a sequence of edges which connect a sequence
of vertices, but with the added restriction that the edges all be directed in the same direction.
Input
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts
with two integers N and D, which indicates the number of nodes in the tree and the restricted value.
The following line contains N integers, a1, a2, …, ai
, …, aN , which indicates the i-th node’s weighted
value. Then N − 1 lines follow, every line contains two integers u, v (1 ≤ u, v ≤ N), which means there
is a path between u-th node and v-th node.
Output
For each test case, output one line containing ‘Case #x: y’, where x is the test case number (starting
from 1) and y is the length of LRIP of this tree.
Unofficial clarification: The last N −1 lines for each testcase describe edges, not paths. These edges
are undirected (i.e. you can make it a directed edge in either direction), and the length of a path is the
number of nodes on it.
Limits:
1 ≤ T ≤ 10
1 ≤ ai ≤ 10^5
, 1 ≤ i ≤ N
1 ≤ N, D ≤ 10^5
题目大意:给一棵带点权的树,求树上的一条最长不下降路径,使得最大结点和最小结点的差不超过一个给定的D。
思路:其实直接遍历+启发式合并大概也可以做,但是用树的点分治要容易地多……
首先,对于每次分治,找到一个分治中心root,寻找“所有”经过root的路径,并把root删去,继续分治。
那么,如何找到经过root的路径呢?
假设root的儿子为list(son),依次遍历每个儿子,并维护上升路径的集合,再从所有下降路径中寻找最佳的上升路径。
维护的集合为上升路径的权值+上升路径的深度(假设根为root)。
若上升路径的序列中,权值严格递增,深度严格递减(舍弃多余的路径),那么下降路径寻找最佳上升路径的时候,直接二分即可。
至于维护上面说的集合,可以使用线段树来维护,也可以使用std::map来维护(考验STL水平的时候到了)。
总复杂度为O(n(logn)^2)。
PS:什么是多余的上升路径?设权值为val,深度为dep。若val[u]≥val[v]且dep[u]≥dep[v],那么v在任意时刻都不会比u更优,可以舍弃。因为我们要找的是权值大于等于某个值的深度最大的结点。
代码(0.736S):
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
typedef long long LL; const int MAXV = ;
const int MAXE = MAXV * ; int head[MAXV], val[MAXV], ecnt;
int to[MAXE], nxt[MAXE];
int n, D, T, res; void init() {
memset(head + , -, n * sizeof(int));
ecnt = ;
} void add_edge(int u, int v) {
to[ecnt] = v; nxt[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; nxt[ecnt] = head[v]; head[v] = ecnt++;
} int size[MAXV], maxBranch[MAXV];
bool del[MAXV];
vector<int> nodes; void dfs_size(int u, int f) {
size[u] = ;
maxBranch[u] = ;
for(int p = head[u]; ~p; p = nxt[p]) {
int v = to[p];
if(del[v] || v == f) continue;
dfs_size(v, u);
size[u] += size[v];
maxBranch[u] = max(maxBranch[u], size[v]);
}
nodes.push_back(u);
}
int get_root(int u) {
nodes.clear();
dfs_size(u, -);
int rt = u;
for(int v : nodes) {
maxBranch[v] = max(maxBranch[v], size[u] - size[v]);
if(maxBranch[v] < maxBranch[rt]) rt = v;
}
return rt;
} map<int, int> up; void insert(int val, int len) {
auto x = up.lower_bound(val);
if(x != up.end() && x->second >= len) return ; auto ed = up.upper_bound(val);
//printf("#debug %d %d\n", ed->first, ed->second);
auto it = map<int, int>::reverse_iterator(ed);
while(it != up.rend() && it->second <= len) ++it;
up.erase(it.base(), ed);
up[val] = len;
} void dfs_up(int u, int f, int dep) {
insert(val[u], dep);
for(int p = head[u]; ~p; p = nxt[p]) {
int v = to[p];
if(!del[v] && v != f && val[v] <= val[u])
dfs_up(v, u, dep + );
}
} void dfs_down(int u, int f, int dep) {
auto it = up.lower_bound(val[u] - D);
if(it != up.end()) res = max(res, it->second + dep + );
for(int p = head[u]; ~p; p = nxt[p]) {
int v = to[p];
if(!del[v] && v != f && val[v] >= val[u])
dfs_down(v, u, dep + );
}
} void _work(int u, vector<int> &son) {
up.clear();
up[val[u]] = ;
for(int v : son) {
if(val[v] >= val[u]) dfs_down(v, u, );
if(val[v] <= val[u]) dfs_up(v, u, );
}
}
void work(int rt) {
vector<int> son;
for(int p = head[rt]; ~p; p = nxt[p])
if(!del[to[p]]) son.push_back(to[p]); _work(rt, son);
reverse(son.begin(), son.end());
_work(rt, son);
} void solve(int st) {
int u = get_root(st);
work(u); del[u] = true;
for(int p = head[u]; ~p; p = nxt[p]) {
int v = to[p];
if(!del[v]) solve(v);
}
} int main() {
scanf("%d", &T);
for(int t = ; t <= T; ++t) {
scanf("%d%d", &n, &D);
init();
for(int i = ; i <= n; ++i) scanf("%d", &val[i]);
for(int i = , u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
add_edge(u, v);
} memset(del + , , n * sizeof(bool));
res = ;
solve();
printf("Case #%d: %d\n", t, res);
}
}
小插曲:AC过两天居然改数据rejudge了!然而发现机房居然各种不能上网。用爪机看了看代码,大概就少了处理n=1的情况。后来能上网后随手交交就AC了。其他题似乎也rejudge了o(╯□╰)o,还好我平时写完代码都有自己保存,不然就坑爹了。
UVALive 7148 LRIP(树的分治+STL)(2014 Asia Shanghai Regional Contest)的更多相关文章
- UVALive 7141 BombX(离散化+线段树)(2014 Asia Shanghai Regional Contest)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...
- UVALive 7146 Defeat the Enemy(贪心+STL)(2014 Asia Shanghai Regional Contest)
Long long ago there is a strong tribe living on the earth. They always have wars and eonquer others. ...
- UVALive 7138 The Matrix Revolutions(Matrix-Tree + 高斯消元)(2014 Asia Shanghai Regional Contest)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...
- UVALive 7143 Room Assignment(组合数学+DP)(2014 Asia Shanghai Regional Contest)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...
- UVALive 7147 World Cup(数学+贪心)(2014 Asia Shanghai Regional Contest)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...
- UVALive 7139 Rotation(矩阵前缀和)(2014 Asia Shanghai Regional Contest)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=6 ...
- hdu5071 2014 Asia AnShan Regional Contest B Chat
模拟题: add的时候出现过的则不再添加 close的时候会影响到top rotate(Prior.Choose)的时候会影响到top /*============================== ...
- 2014 Asia AnShan Regional Contest --- HDU 5073 Galaxy
Galaxy Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5073 Mean: 在一条数轴上,有n颗卫星,现在你可以改变k颗 ...
- dp --- 2014 Asia AnShan Regional Contest --- HDU 5074 Hatsune Miku
Hatsune Miku Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5074 Mean: 有m种音符(note),现在要从 ...
随机推荐
- 诡异的C语言实参求值顺序
学了这么久的C语言,竟然第一次碰到这么诡异的实参求值顺序问题,大跌眼镜.果然阅读面太少了! #include<iostream> void foo(int a, int b, int c) ...
- DOTA 2 Match History WebAPI(翻译)
关于DOTA 2 Match History WebAPI 的 源网页地址: http://dev.dota2.com/showthread.php?t=47115 由于源网页全英文,这边做下翻译方便 ...
- 【JAVA】Runtime
1.内存管理:Java提供了无用单元自动收集机制.通过totalMemory()和freeMemory()方法可以知道对象的堆内存有多大,还剩多少.Java 会周期性的回收垃圾对象(未使用的对象),以 ...
- Windows OS上安装运行Apache Kafka教程
Windows OS上安装运行Apache Kafka教程 下面是分步指南,教你如何在Windows OS上安装运行Apache Zookeeper和Apache Kafka. 简介 本文讲述了如何在 ...
- C# 该行已经属于另一个表
DataTable dtSource = (DataTable)this.gridControl1.DataSource; DataRow[] dr = dtSource.Select("c ...
- java读取项目中文件路径及乱码解决
this.getClass.getResource(path).getPath(); 如果出现中文乱码,可以使用java.net.URLDecoder.decode方法进行处理 如:URLDecode ...
- MySQL性能分析及explain的使用
MySQL性能分析及explain用法的知识 1.使用explain语句去查看分析结果 如explain select * from test1 where id=1;会出现:id selectty ...
- 20145215实验二 Java面向对象程序设计
一.实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 二.实验步骤 (一)单元测试 (1)三种代码 伪代码: ...
- SQL SERVER 数据库操作脚本
创建数据库 create Database MYDB on ( Name=mydb_dat, FileName='c:\data\mydate.mdf',size=10,maxsize=50 ) LO ...
- 【30集iCore3_ADP出厂源代码(ARM部分)讲解视频】30-1 前言
视频简介: 该视频介绍收到iCore3应用开发平台后如何获取出厂代码,以 及如何下载出厂代码到应用开发平台中. 源视频包下载地址: http://pan.baidu.com/s/1nuUZW17 ...