BZOJ2870 最长道路
题意:给定树,有点权。求一条路径使得最小点权 * 总点数最大。只需输出这个最大值。5w。
解:树上路径问题,点分治。
考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入的节点的时候,只需在val比它大的点中选出一个最大的d2,这树状数组就可以做到。
当2是新插入的节点时候,好像需要凸包了?但是我们完全不虚啊,因为我们倒序枚举子树就能让2在1之前插入。
于是正反枚举两次子树,拿树状数组维护一下后缀最大值就行了。
复杂度O(nlog2n)
/**
* There is no end though there is a start in space. ---Infinity.
* It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
* Only the person who was wisdom can read the most foolish one from the history.
* The fish that lives in the sea doesn't know the world in the land.
* It also ruins and goes if they have wisdom.
* It is funnier that man exceeds the speed of light than fish start living in the land.
* It can be said that this is an final ultimatum from the god to the people who can fight.
*
* Steins;Gate
*/ #include <bits/stdc++.h> #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex) typedef long long LL;
const int N = , INF = 0x3f3f3f3f; struct Edge {
int nex, v;
}edge[N << ], edge2[N << ]; int tp, tp2; int e[N], n, siz[N], _n, root, small, e2[N], xx, d[N], Val[N];
LL val[N], X[N], ans;
bool del[N]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} inline void add2(int x, int y) {
tp2++;
edge2[tp2].v = y;
edge2[tp2].nex = e2[x];
e2[x] = tp2;
return;
} namespace ta {
int ta[N];
inline void add(int x, int v) {
x = xx + - x;
for(int i = x; i <= xx; i += i & (-i)) {
ta[i] = std::max(ta[i], v);
}
return;
}
inline void del(int x) {
x = xx + - x;
for(int i = x; i <= xx; i += i & (-i)) {
ta[i] = -INF;
}
return;
}
inline int getMax(int x) {
x = xx + - x;
int ans = -INF;
for(int i = x; i; i -= i & (-i)) {
ans = std::max(ans, ta[i]);
}
return ans;
}
} void getroot(int x, int f) {
siz[x] = ;
int large = ;
forson(x, i) {
int y = edge[i].v;
if(y == f || del[y]) continue;
getroot(y, x);
siz[x] += siz[y];
if(siz[y] > large) {
large = siz[y];
}
}
if(_n - siz[x] > large) {
large = _n - siz[x];
}
if(small > large) {
small = large;
root = x;
}
return;
} void DFS_1(int x, int f) {
siz[x] = ;
d[x] = d[f] + ;
Val[x] = std::min(Val[f], (int)val[x]);
ans = std::max(ans, X[Val[x]] * (d[x] + ta::getMax(Val[x])));
forson(x, i) {
int y = edge[i].v;
if(del[y] || y == f) continue;
DFS_1(y, x);
siz[x] += siz[y];
}
return;
} void DFS_2(int x, int f) {
ta::add(Val[x], d[x] + );
forson(x, i) {
int y = edge[i].v;
if(y == f || del[y]) continue;
DFS_2(y, x);
}
return;
} void DFS_3(int x, int f) {
ta::del(Val[x]);
forson(x, i) {
int y = edge[i].v;
if(del[y] || y == f) {
continue;
}
DFS_3(y, x);
}
return;
} void poi_div(int x) {
small = INF;
getroot(x, );
x = root; d[x] = ;
Val[x] = val[x];
ta::add(Val[x], );
forson(x, i) {
int y = edge[i].v;
if(del[y]) continue;
DFS_1(y, x);
DFS_2(y, x);
}
DFS_3(x, );
// ---------
for(int i = e2[x]; i; i = edge2[i].nex) {
int y = edge2[i].v;
if(del[y]) continue;
DFS_1(y, x);
DFS_2(y, x);
}
ans = std::max(ans, X[val[x]] * ta::getMax(val[x]));
DFS_3(x, ); del[x] = ;
forson(x, i) {
int y = edge[i].v;
if(del[y]) continue;
_n = siz[y];
poi_div(y);
}
return;
} int main() { scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%lld", &val[i]);
X[i] = val[i];
}
std::sort(X + , X + n + );
xx = std::unique(X + , X + n + ) - X - ;
for(int i = ; i <= n; i++) {
val[i] = std::lower_bound(X + , X + xx + , val[i]) - X;
}
ans = X[xx];
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y); add(y, x);
}
for(int x = ; x <= n; x++) {
forson(x, i) {
add2(x, edge[i].v);
}
} poi_div(); printf("%lld\n", ans);
return ;
}
AC代码
题外话:感觉能树形DP,但是要线段树合并 + 凸包合并,虚的一批...
还发现了一个O(nlogn)的做法,只需多叉转二叉然后O(n) - O(1)lca即可实现,瓶颈在于排序...
然而这题是边分治模板题...
BZOJ2870 最长道路的更多相关文章
- BZOJ2870—最长道路tree
最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都 ...
- BZOJ2870: 最长道路tree
题解: 子树分治的做法可以戳这里:http://blog.csdn.net/iamzky/article/details/41120733 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...
- bzoj2870最长道路tree——边分治
简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 有几个不同的做法: 1.sort+并查集+树的直径.边从大到小加入 ...
- BZOJ2870 最长道路tree(并查集+LCA)
题意 (n<=50000) 题解 #include<iostream> #include<cstring> #include<cstdio> #include ...
- [BZOJ2870]最长道路tree:点分治
算法一:点分治+线段树 分析 说是线段树,但是其实要写树状数组卡常. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(register ...
- 【BZOJ2870】最长道路(边分治)
[BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...
- 【BZOJ2870】最长道路tree 点分治+树状数组
[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...
- 【bzoj2870】最长道路tree 树的直径+并查集
题目描述 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 输入 第一行N 第二行N个数分别表示1~N的点权v[i] 接下来N-1行每 ...
- 【BZOJ2870】最长道路
权限题 题意 给出一棵树,点有点权,找到树上的一条路径使得路径上点的个数和其中点权最小的点的点权之积最大,输出最大值. Sol 边分治板子题啦. 边分治后对于分出来的两棵子树 , 按到左右根的最小点权 ...
随机推荐
- webpack安装、基本配置
文章结构: 什么是webpack? 安装webpack webpack基本配置 一.什么是webpack? 在学习react时发现大部分文章都是react和webpack结合使用的,所以在学react ...
- Linux 环境 Java JDK 安装&基本配置
索引: 目录索引 参看代码 GitHub: jdk.txt 一.Linux (DeepinOS) 环境 1.官网下载 jdk-8u112-linux-x64.tar.gz 2.创建目录 mkdir - ...
- 字符是否为SQL的保留字
要想知道字符是否为MS SQL Server保留字,那我们必须把SQL所有保留字放在一个数据集中.然后我们才能判断所查找的字符是否被包含在数据集中. MS SQL Server保留字: ) = 'ad ...
- Nagle 算法
1. Nagel算法 TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认.为了尽可能的利用网络带宽,TCP总是希望尽可能的发 ...
- javaweb学习--jsp
阅读电子书<Java Web从入门到精通>密码:461c,学习JavaWeb基础知识.由于本人已有html基础,所以直接略过前面部分,进入jsp学习 jsp页面添加库引用,引入项目文件 引 ...
- Python模块time、datetime
模块: 模块是一系列常用功能的集合体,一个py文件就是一个模块. 一.模块的作用: 1.从文件级别组织程序,方便管理,随着程序的发展,功能越来越多,我们通常将程序分成一个个py文件,这样做程序的结构更 ...
- Go语言学习笔记-流程控制(二)
Go语言流程控制 字典类型Map 1.上节遗留:map字典类型 变量声明:var myMap map[string] PersonInfo 其中,myMap是变量名,string是键的类型,Perso ...
- Java 集合系列(一)
Java集合系列文章将以思维导图为主要形式来展示知识点,让零碎的知识形成体系. 这篇文章主要介绍的是[Java 集合的基本知识],即Java 集合简介. 毕业出来一直使用 PHP 进行开发,对于大学所 ...
- SQLServer之修改PRIMARY KEY
使用SSMS数据库管理工具修改PRIMARY KEY 1.连接数据库,选择数据表->右键点击->选择设计(或者展开键,选择要修改的键,右键点击,选择修改,后面步骤相同). 2.选择要修改的 ...
- #021 Java复习第一天
上学期在慧河工作室学习简单过java到面向对象就停止了 现在有事情又要用到java发现全忘了..... 快速复习一下 网课PPT 计算机: 硬件 + 软件 主要硬件: cpu :cpu是一个计算机的运 ...