简化版描述:

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

有几个不同的做法:

1.sort+并查集+树的直径。边从大到小加入,并查集维护连通块,记录连通块的直径的两个端点,合并连通块的时候更新直径,并且用len*bian[i].w更新答案

  有排序,O(nlogn)

2.点分治+树状数组。点分治路径合并的时候挺恶心。先都扫一遍所有子树,把路径最小值作为下标,链长作为权值放进树状数组里。

  再枚举子树搜一遍,先减去当前子树的贡献,再搜的时候从树状数组找后缀最大值。思想就是钦定最小值在当前子树的某个路径中

  O(nlog^2)

3.点分治

  把过重心的子树分成两堆递归?不懂。。。O(nlogn)

  代码太长,还不如写边分治

4.边分治

https://blog.csdn.net/litble/article/details/80853633

 本身其实点分治还可以暴力枚举重心子树的所有兄弟然后双指针,从而不用树状数组,但是复杂度是O(度数^2nlogn)的。不优秀

边分治就两个儿子自然好办啦

三度化然后边分治,两个子树的路径存进两个数组,按照最小值sort,然后倒序枚举双指针。记录最小值不小于当前钦定子树的最大的深度,左右各做一遍即可

过虚点其实一定过了x,所以虚点权值定为x的权值。

虚边的权值就是0,实边是1,两点链长是深度+1

代码:

注意,如果对面的儿子没有选择一个点,那么不能计算当前的中心边的权值

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define mk(x,y) make_pair(x,y)
#define fi first
#define se second
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=+;
const int inf=0x3f3f3f3f;
int n;
int tot;
int val[N];
struct node{
int nxt,to;
int w;
}e[*N],bian[*N];
int cnt1=,cnt2;
int hd[N],pre[N];
ll ans;
void add(int x,int y,int z){
e[++cnt1].nxt=hd[x];
e[cnt1].to=y;
e[cnt1].w=z;
hd[x]=cnt1;
}
void add_c(int x,int y){
bian[++cnt2].nxt=pre[x];
bian[cnt2].to=y;
pre[x]=cnt2;
}
void rebuild(int x,int fa){
int ff=;
for(reg i=pre[x];i;i=bian[i].nxt){
int y=bian[i].to;
if(y==fa) continue;
if(!ff){
add(x,y,);
add(y,x,);
ff=x;
}else{
int tmp=++tot;
val[tmp]=val[x];
add(ff,tmp,);add(tmp,ff,);
add(tmp,y,);add(y,tmp,);
ff=tmp;
}
rebuild(y,x);
}
} pair<int,int>ls[N],rs[N];
int lsc,rsc;
bool cmp(pair<int,int>A,pair<int,int>B){
if(A.fi==B.fi) return A.se<B.se;
return A.fi<B.fi;
}
int totsz;
int rt1,rt2,edge;
bool vis[*N];
int sz[N],mx;
void dfs1(int x,int fa){
sz[x]=;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[i]) continue;
dfs1(y,x);
int now=max(sz[y],totsz-sz[y]);
if(now<mx) {
mx=now;rt1=x;rt2=y;edge=i;
}
sz[x]+=sz[y];
}
}
void dfs2(int x,int fa,int mi,int dep,int typ){
if(typ==){
ls[++lsc]=mk(mi,dep);
}else{
rs[++rsc]=mk(mi,dep);
}
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa||vis[i]) continue;
dfs2(y,x,min(mi,val[y]),dep+e[i].w,typ);
}
}
void divi(int x,int from ){
//cout<<" divi "<<x<<" "<<totsz<<" from "<<from<<endl;
if(totsz==) return; rt1=rt2=edge=;
mx=inf;
dfs1(x,);
//cout<<" rt1 "<<rt1<<" rt2 "<<rt2<<" sz "<<sz[rt1]<<" "<<sz[rt2]<<endl;
vis[edge]=vis[edge^]=;
lsc=rsc=;
dfs2(rt1,,val[rt1],,);
dfs2(rt2,,val[rt2],,);
sort(ls+,ls+lsc+,cmp);
sort(rs+,rs+rsc+,cmp);
int mxdep=;
int ptr=rsc;
for(reg i=lsc;i>=;--i){
while(ptr&&rs[ptr].fi>=ls[i].fi){
mxdep=max(mxdep,rs[ptr].se);--ptr;
}
ans=max(ans,(ll)((ll)mxdep+e[edge].w+ls[i].se+)*ls[i].fi);
}
mxdep=;ptr=lsc;
for(reg i=rsc;i>=;--i){
while(ptr&&ls[ptr].fi>=rs[i].fi){
mxdep=max(mxdep,ls[ptr].se);--ptr;
}
ans=max(ans,(ll)((ll)mxdep+e[edge].w+rs[i].se+)*rs[i].fi);
}
int szrt1=totsz-sz[rt2];
int szrt2=sz[rt2];
int tmprt1=rt1,tmprt2=rt2;
totsz=szrt1;
divi(tmprt1,x);
totsz=szrt2;
divi(tmprt2,x);
}
int main(){
rd(n);
for(reg i=;i<=n;++i) rd(val[i]),ans=max(ans,(ll)val[i]);
int x,y;
for(reg i=;i<n;++i){
rd(x);rd(y);
add_c(x,y);add_c(y,x);
}
tot=n;
rebuild(,);
totsz=tot;
//cout<<" tot "<<tot<<endl;
divi(,);
printf("%lld",ans);
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2019/2/25 9:29:02
*/

bzoj2870最长道路tree——边分治的更多相关文章

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

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

  2. BZOJ2870—最长道路tree

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

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

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

  4. BZOJ2870: 最长道路tree

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

  5. bzoj 2870 最长道路tree——边分治

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2870 关于边分治:https://www.cnblogs.com/Khada-Jhin/p/ ...

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

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

  7. 【BZOJ2870】最长道路(边分治)

    [BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...

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

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

  9. BZOJ2870 最长道路

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

随机推荐

  1. [UWP 自定义控件]了解模板化控件(2):模仿ContentControl

    ContentControl是最简单的TemplatedControl,而且它在UWP出场频率很高.ContentControl和Panel是VisualTree的基础,可以说几乎所有VisualTr ...

  2. MPI-Hydra Process Managerment Framework

    1. 概述2. 执行过程和控制流 官方文档地址:https://wiki.mpich.org/mpich/index.php/Hydra_Process_Management_Framework 1. ...

  3. 【亲测有效】Kali Linux无法安装网易云音乐的解决方案

    问题描述 由于 Kali Linux 的内核是基于 Debian 的,我们在安装网易云音乐的时候更偏向于选择安装网易云音乐 v1.1.0 deepin15(64位) 的包,可是我发现在安装过程中,无法 ...

  4. Webpack 2 视频教程

    这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲解的. 这个基本就是目前 ...

  5. 计算机网络什么是OSI7层模型、TCP/IP4层模型理解

    模型图解 应用层 就是最顶层的.通常指的应用程序初始走的协议比如有 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层 主要对数据应用层的数据包进行加密 会话层 建立.管理. ...

  6. ASS字幕制作

    虽然不常做视频,但正因为是偶尔用到,所以总是记不牢,特此笔记. Name 字体名称?Fontname 字体名称(\fn冬青黑体简体中文 W3)(\fnVogueSans)(例:\N{\fn冬青黑体简体 ...

  7. vue全局 关键字搜索 v-search

    一款基于 vuejs & weui 的全屏搜索组件:https://www.npmjs.com/package/vue-search

  8. XMLHttpRequest.withCredentials

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials var xhr = new XMLHtt ...

  9. JavaScript 字符串与数组互转,并保持数据去重、排序功能

    var valueArr = new Array(); if( $("input[name='type']").val() != ""){ valueArr = ...

  10. [转帖]龙芯下一代处理器微结构GS464E细节曝光

    龙芯下一代处理器微结构GS464E细节曝光 [日期:2015-05-26] 来源:Linux公社  作者:Linux [字体:大 中 小] http://www.linuxidc.com/Linux/ ...