题目描述

给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大。
其中链长度定义为链上点的个数。

输入

第一行N
第二行N个数分别表示1~N的点权v[i]
接下来N-1行每行两个数x、y,表示一条连接x和y的边

输出

一个数,表示最大的痛苦程度。

样例输入

3
5 3 5
1 2
1 3

样例输出

10


题解

树的直径+并查集

首先肯定是把权值从大到小排序,按照顺序加点,维护每个连通块的最长链乘以当前点权值作为贡献。

那么如何在加上一条边,连接两棵树后快速得出新的直径呢?

一个结论:将两棵树连成一棵,新树的直径的两端点只有可能是原来两棵树两条直径四个端点中的某两个。

证明不太容易表述。。。简单画一画就差不多出来了。实在不行可以先推加一个点的情况,然后再推加一棵树。

于是使用并查集维护树的直径长度及端点位置,使用倍增LCA求距离,就做完了。。。

注意需要开long long。

时间复杂度 $O(n\log n)$

#include <cstdio>
#include <algorithm>
#define N 50010
using namespace std;
typedef long long ll;
int v[N] , id[N] , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][17] , deep[N] , log[N] , f[N] , px[N] , py[N];
ll ans = 0;
bool cmp(int a , int b)
{
return v[a] > v[b];
}
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x)
{
int i;
for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x][0])
fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
}
inline int lca(int x , int y)
{
int i;
if(deep[x] < deep[y]) swap(x , y);
for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
if(deep[x] - deep[y] >= (1 << i))
x = fa[x][i];
if(x == y) return x;
for(i = log[deep[x]] ; ~i ; i -- )
if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
x = fa[x][i] , y = fa[y][i];
return fa[x][0];
}
inline int dis(int x , int y)
{
return deep[x] + deep[y] - (deep[lca(x , y)] << 1);
}
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
void solve(int x)
{
int i , tx , ty , t , vm , vx , vy;
for(i = head[x] ; i ; i = next[i])
{
if(f[to[i]])
{
tx = find(x) , ty = find(to[i]) , vm = -1;
if(vm < (t = dis(px[tx] , py[tx]))) vm = t , vx = px[tx] , vy = py[tx];
if(vm < (t = dis(px[ty] , py[ty]))) vm = t , vx = px[ty] , vy = py[ty];
if(vm < (t = dis(px[tx] , px[ty]))) vm = t , vx = px[tx] , vy = px[ty];
if(vm < (t = dis(px[tx] , py[ty]))) vm = t , vx = px[tx] , vy = py[ty];
if(vm < (t = dis(py[tx] , px[ty]))) vm = t , vx = py[tx] , vy = px[ty];
if(vm < (t = dis(py[tx] , py[ty]))) vm = t , vx = py[tx] , vy = py[ty];
f[ty] = tx , px[tx] = vx , py[tx] = vy;
}
}
tx = find(x) , ans = max(ans , (ll)v[x] * (dis(px[tx] , py[tx]) + 1));
}
int main()
{
int n , i , x , y;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]) , id[i] = i;
for(i = 2 ; i <= n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1;
dfs(1);
sort(id + 1 , id + n + 1 , cmp);
for(i = 1 ; i <= n ; i ++ )
f[id[i]] = px[id[i]] = py[id[i]] = id[i] , solve(id[i]);
printf("%lld\n" , ans);
return 0;
}

【bzoj2870】最长道路tree 树的直径+并查集的更多相关文章

  1. BZOJ 2870: 最长道路tree 树的直径+并查集

    挺好的一道题. 把所有点都离线下来,一个个往里加入就行了. #include <cstdio> #include <algorithm> #define N 100003 #d ...

  2. 【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目描述 给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林:询问一个点能到达的最远的点与该点的距离.强制在线. $n\le 3\times 10^5$ ,$ ...

  3. BZOJ2870—最长道路tree

    最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都 ...

  4. bzoj2870最长道路tree——边分治

    简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数.   有几个不同的做法: 1.sort+并查集+树的直径.边从大到小加入 ...

  5. hdu 4514(树的直径+并查集)

    湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  6. 求树的直径+并查集(bfs,dfs都可以)hdu4514

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 这题主要是叫我们求出树的直径,在求树的直径之前要先判断一下有没有环 树的直径指的就是一棵树上面距 ...

  7. Codeforces 455C Civilization:树的直径 + 并查集【合并树后直径最小】

    题目链接:http://codeforces.com/problemset/problem/455/C 题意: 给你一个森林,n个点,m条边. 然后有t个操作.共有两种操作: (1)1 x: 输出节点 ...

  8. loj6038「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目传送门 https://loj.ac/problem/6038 题解 根据树的直径的两个性质: 距离树上一个点最远的点一定是任意一条直径的一个端点. 两个联通块的并的直径是各自的联通块的两条直径的 ...

  9. Codeforces 516D - Drazil and Morning Exercise(树的直径+并查集)

    Codeforces 题目传送门 & 洛谷题目传送门 这是一道 jxd 的作业题,感觉难度不是特别大(虽然我并没有自己独立 AC,不过也可能是省选结束了我的脑子也没了罢(((,就随便写写罢 u ...

随机推荐

  1. Tips & Tricks Learned Releasing an Hybrid App Using Steroids.js

    http://marcgg.com/blog/2014/04/09/phonegap-steroids-hybrid-native-app-tips/

  2. JSON初体验(三):FastJson解析

    JSON解析之FastJson(阿里巴巴解析开源) 特点: Fastjson是一个Java语言编写的高性能功能完善的JSON库,它采用的 是一种"假定有序快速匹配"的算法,把JSO ...

  3. Tomcat 8.5 基于 Apache Portable Runtime(APR)库性能优化

    Tomcat可以使用Apache Portable Runtime来提供卓越的性能及可扩展性,更好地与本地服务器技术的集成.Apache Portable Runtime是一个高度可移植的库,位于Ap ...

  4. 北京Uber优步司机奖励政策(2月26日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  5. P1209 [USACO1.3]修理牛棚 Barn Repair

    P1209 [USACO1.3]修理牛棚 Barn Repair 题目描述 在一个夜黑风高,下着暴风雨的夜晚,farmer John的牛棚的屋顶.门被吹飞了. 好在许多牛正在度假,所以牛棚没有住满. ...

  6. atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?

    atomic不是绝对的线程安全.atomic的本意是指属性的存取方法是线程安全的,并不保证整个对象是线程安全的 @property (atomic, assign) int intA; //线程A f ...

  7. records_in_range start_key, end_key

    select * from federatedTest where name='aaa';(gdb) p *start_key$2 = {key = 0x7f64f4103be8 "&quo ...

  8. PS 旋转任意角度的照片

    1.选择标尺工具 2.在图片上画一个线,然后工具栏--图像--图像旋转

  9. html div内第二行文字显示不下的时候才用省略号代替 css实现

    有时候文字太多,但为了美观想要在第二行的时候才显示省略号,而不是第一行超出马上就出现省略号 下面是css代码: overflow:hidden;text-overflow: ellipsis;//显示 ...

  10. 【WXS数据类型】String

    属性: 名称 值类型 说明 [String].constructor [String] 返回值为“String”,表示类型的结构字符串 [String].length [Number] 返回该字符串的 ...