题目描述

给定一棵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. Lucene第一讲——概述与入门

    一.概述 1.什么是Lucene? Lucene是apache下的一个开源的全文检索引擎工具包. 它为软件开发人员提供一个简单易用的工具包(类库),以方便的在目标系统中实现全文检索的功能. 2.能干什 ...

  2. 在同一台机器上启动多个tomcat服务(转)

    转载:https://blog.csdn.net/wangxy799/article/details/53957770 1.案例:配置一台机上配置三个Tomcat 2.方法1:[只用修改第一个以外To ...

  3. 利用Powershell查询AD中账号属性

    标签:AD账号信息 最后登录时间 最后修改密码.SID 账号SID 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://hubuxcg ...

  4. MVC、MVVM

    一.MVC 所谓的 MVC 是指: Model: 数据的拥有者,实现具体的业务逻辑. View: 具体的用户界面,如按钮.列表.图片. Controller: 负责将 View 中用户的动作传达给 M ...

  5. records_in_range start_key, end_key

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

  6. editText设置最大长度

    xml中可以设置为: <EditText android:layout_width = "fill_parent" android:layout_height = " ...

  7. 【SpringCloud】第四篇:断路器(Hystrix)

    前言: 必需学会SpringBoot基础知识 简介: spring cloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理.服务发现.断路器.路由.微代理.事件总线.全局锁.决策竞选. ...

  8. hello-jni Android.mk文件简析

    #删除旧变量 LOCAL_PATH := $(call my-dir) #返回当前目录 include $(CLEAR_VARS) #删除旧变量 #设置新变量 LOCAL_MODULE := hell ...

  9. 初学Direct X(10)—— D3D基础预备知识

    初学Direct X(10) -- D3D基础预备知识 1. 像素格式 D3DFMT_X8R8G8B8(F) X:未加使用 8:8位用于显示 B:用于显示蓝色 F:浮点像素类型 以下三个较为常用,使用 ...

  10. win 下通过dos命令格式化磁盘

    该命令可以解决好多问题,比如: 1.u盘作为启动后,如何恢复成正常的u盘 1.win + r ->cmd 进入dos模式 2.输入diskpart后回车,点击确定,进入diskpart命令的交互 ...