最长道路tree

Description

  H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样。每个路口都有很多车辆来往,所以每个路口i都有一个拥挤程度v[i],我们认为从路口s走到路口t的痛苦程度为s到t的路径上拥挤程度的最小值,乘上这条路径上的路口个数所得的积。现在请你求出痛苦程度最大的一条路径,你只需输出这个痛苦程度。

Simple Description

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

Input

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

Output

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

Sample Input

3
5 3 5
1 2
1 3

Sample Output

10

样例解释

  选择从1到3的路径,痛苦程度为min(5,5)*2=10

HINT

  100%的数据n<=50000

  其中有20%的数据树退化成一条链

  所有数据点权<=65536

  Hint:建议答案使用64位整型

思路

  首先我们看一下数据范围,想一想点分治似乎就哈哈了,所以我们需要换一个思路。我们考虑一下,知道只有路径上的最小值才能对答案有贡献,所以我们可以把点的权值从大到小排序,这样我们就可以在插点的同时,维护经过当前点的最长路径,从而更新路径最大值就可以了。为什么呢?因为我们是按照权值由大到小的顺序进行的建树,所以每一次统计路径时,当前点就是最小值。

  下面我们想,用什么维护路径长度呢?树链剖分。用什么维护最长长度呢?树的直径加并查集。所以这些放在一起,就是AC。

代码

#include <stdio.h>
#include <algorithm>
using namespace std;
#define N 50001
int n,idx,cnt;
int head[N];
int to[N<<1];
int nxt[N<<1];
int val[N],son[N];
int fa[N],top[N];
int f[N],need[N];
int level[N],size[N];
long long ans;int dis[N];
int root1[N],root2[N];
bool vis[N];
bool cmp(const int &a,const int &b)
{return val[a]>val[b];}
int find_anc(int x)
{return (f[x]==x)?x:f[x]=find_anc(f[x]);}
void add(int a,int b)
{
nxt[++idx]=head[a];
head[a]=idx;
to[idx]=b;
}
void dfs(int p,int from)
{
level[p]=level[from]+1;
size[p]=1,fa[p]=from;
for(int i=head[p];i;i=nxt[i])
if(to[i]!=from)
{
dis[to[i]]=dis[p]+1;dfs(to[i],p);
size[p]+=size[to[i]];
if(size[son[p]]<size[to[i]]) son[p]=to[i];
}
}
void dfs2(int p,int from)
{
if(son[p]) dfs2(son[p],from);
top[p]=from;
for(int i=head[p];i;i=nxt[i])
if(to[i]!=fa[p]&&to[i]!=son[p])
dfs2(to[i],to[i]);
}
int find_lca(int a,int b)
{
while(top[a]!=top[b])
{
if(level[top[a]]>level[top[b]])
swap(a,b);
b=fa[top[b]];
}
return (level[a]<level[b])?a:b;
}
int find_dis(int a,int b)
{
int tmp=find_lca(a,b);
return dis[a]+dis[b]-2*dis[tmp];
}
void merge(int x,int y)
{
int fx=find_anc(x);
int fy=find_anc(y);
if(fx==fy) return;
f[fy]=fx;int &p1=root1[fx],&p2=root2[fx];
int r1=root1[fx],r2=root2[fx],r3=root1[fy],r4=root2[fy];
int l1=find_dis(r1,r2),l2=find_dis(r1,r3),l3=find_dis(r1,r4);
int l4=find_dis(r2,r3),l5=find_dis(r2,r4),l6=find_dis(r3,r4);
int mx=max(l1,max(l2,max(l3,max(l4,max(l5,l6)))));
if(l1==mx) p1=r1,p2=r2;
else if(l2==mx) p1=r1,p2=r3;
else if(l3==mx) p1=r1,p2=r4;
else if(l4==mx) p1=r2,p2=r3;
else if(l5==mx) p1=r2,p2=r4;
else if(l6==mx) p1=r3,p2=r4;
ans=max(ans,1ll*(mx+1)*val[x]);
}
void add_point(int p)
{
vis[p]=true;
for(int i=head[p];i;i=nxt[i])
if(vis[to[i]]) merge(p,to[i]);
}
int main()
{
//freopen("Choose.in","r",stdin);
//freopen("Choose.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
need[i]=f[i]=root1[i]=root2[i]=i;
}
sort(need+1,need+n+1,cmp);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs(1,0),dfs2(1,1);
for(int i=1;i<=n;i++) add_point(need[i]);
printf("%I64d",ans);
}

BZOJ2870—最长道路tree的更多相关文章

  1. BZOJ2870: 最长道路tree

    题解: 子树分治的做法可以戳这里:http://blog.csdn.net/iamzky/article/details/41120733 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...

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

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

  3. BZOJ2870 最长道路tree(并查集+LCA)

    题意 (n<=50000) 题解 #include<iostream> #include<cstring> #include<cstdio> #include ...

  4. [BZOJ2870]最长道路tree:点分治

    算法一:点分治+线段树 分析 说是线段树,但是其实要写树状数组卡常. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(register ...

  5. 【BZOJ2870】最长道路tree 点分治+树状数组

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

  6. 【bzoj2870】最长道路tree 树的直径+并查集

    题目描述 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 输入 第一行N 第二行N个数分别表示1~N的点权v[i] 接下来N-1行每 ...

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

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

  8. BZOJ2870 最长道路

    题意:给定树,有点权.求一条路径使得最小点权 * 总点数最大.只需输出这个最大值.5w. 解:树上路径问题,点分治. 考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入 ...

  9. 2870: 最长道路tree

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2870 思路 先把树转化为二叉树 再链分治 %%yyb 代码 #include <ios ...

随机推荐

  1. 3 View - Request对象

    1.HttpReqeust对象 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象 视图函数的第一个参数是HttpRequest对象 在django.http模块中定义了Htt ...

  2. TCP/IP网络编程之地址族与数据序列

    分配IP地址和端口号 IP是Internet Protocol(网络协议)的简写,是为收发网络数据而分配给计算机的值.端口号并非赋予计算机的值,而是为区分程序中创建的套接字而分配给套接字的序号 网络地 ...

  3. win8 远程桌面时提示凭证不工作问题的终极解决办法

    环境说明 远程办公电脑(放置于公司.自用办公电脑.win8系统) 远程连接客户机(放置于家中.家庭日常所用.win8系统) 故障现象 最近在使用远程桌面连接公司的办公电脑时,突然发现win8系统总是无 ...

  4. 使用WMI Filter 实现组策略的筛选!

    今天接到一个客户的一个问题,提到需要分系统版本分发相应的MSI程序.比如简体版接受简体版的分发程序,繁体版接受繁体版的分发程序!这个建立组策略的不同版本分发本身不会太难,我们只需要建立两个不同组策略分 ...

  5. 强命名实用程序(SN.exe)

    不要在普通的命令行窗口中编译,请先打开C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Visual Studio 2010 ...

  6. 07 JVM 是如何实现反射的

    Java 中的反射 反射是 Java 语言的一个相当重要的特性,它允许正在运行的 Java 程序观测,甚至是修改程序的动态行为. 我们可以通过 Class 对象枚举该类中的所有方法,还可以通过 Met ...

  7. [python][django学习篇][2]创建django app

    推荐学校django博客:http://pythonzh.cn/post/8/ django app 可以理解为一个文件夹: 里面包含了相关功能的代码.通过manage.py来创建 web app 激 ...

  8. Python之协程的实现

    1.Python里面一般用gevent实现协程协程, 而协程就是在等待的时候切换去做别的操作,相当于将一个线程分块,充分利用资源 (1)低级版协程的实现 import gevent def test1 ...

  9. import from 相对路径

    项目目录 - server - static - src - - stroe - - router - - main.js - app.js src为前端文件,src目录下有main.js代码如下 i ...

  10. 【转】Unity3D学习日记(一)使用UGUI制作虚拟摇杆

    http://blog.csdn.net/begonia__z/article/details/51170059 如今手机游戏玩法多种多样,尤其使用虚拟摇杆进行格斗类游戏开发或者是MMORPG成为了主 ...