bzoj2870最长道路tree——边分治
简化版描述:
有几个不同的做法:
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——边分治的更多相关文章
- 【BZOJ2870】最长道路tree 点分治+树状数组
[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...
- BZOJ2870—最长道路tree
最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都 ...
- [BZOJ2870]最长道路tree:点分治
算法一:点分治+线段树 分析 说是线段树,但是其实要写树状数组卡常. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(register ...
- BZOJ2870: 最长道路tree
题解: 子树分治的做法可以戳这里:http://blog.csdn.net/iamzky/article/details/41120733 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...
- bzoj 2870 最长道路tree——边分治
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2870 关于边分治:https://www.cnblogs.com/Khada-Jhin/p/ ...
- BZOJ2870 最长道路tree(并查集+LCA)
题意 (n<=50000) 题解 #include<iostream> #include<cstring> #include<cstdio> #include ...
- 【BZOJ2870】最长道路(边分治)
[BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...
- 【bzoj2870】最长道路tree 树的直径+并查集
题目描述 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 输入 第一行N 第二行N个数分别表示1~N的点权v[i] 接下来N-1行每 ...
- BZOJ2870 最长道路
题意:给定树,有点权.求一条路径使得最小点权 * 总点数最大.只需输出这个最大值.5w. 解:树上路径问题,点分治. 考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入 ...
随机推荐
- CentOS 7.2:Failed to start IPv4 firewall with iptables
问题 系统是centos7.2,且已经安装了iptables服务,但是在执行启动命令后,却报了iptables服务无法正常启动的错误. 启动命令如下: systemctl start iptables ...
- C#断点续传下载。
断点续传 最近在优化之前的下载流程,仅此篇幅留作笔记之用,日后其他研究此类问题的伙伴可以马上了解原理和开发,减少开发成本. 原理:断点续传目前比较通用的是使用HTTP续传方式,相关的资料可以通过访问: ...
- Redis_简单使用
可基于内存也可持久化的Key-Value(字典, Remote Dictionary Server,远程字典服务器)数据库. 客户端:http://redis.io/clients 命令:http:/ ...
- 太白教你学python---博客分类目录
太白非技术类随笔(持续更新中...猛击这里!!!) python基础 python基础一 pytcharm安装详细教程 python基础二 python基础数据类型 Python最详细,最深入的代码块 ...
- part 1
注意:本次源码分析选择2.0.3(因为不支持IE6.7.8,就少了很多兼容的hack的写法,对了解jQuery的实现原理有很大的帮助) 1.jQuery有不同的版本,从2.x版本便不再支持IE6.7. ...
- required: true,el-upload :action="UploadUrl()"
<el-form-item label="所属班级:" prop="Name" :rules="[{ required: true, messa ...
- pair work结对编程(张艺 杨伊)
一.结对编程人员: 张艺(学号后三位:185) 杨伊(学号后三位:151) 二.这是我们工作的样子:(图片) 三.结对编程优缺点: 优点: 1.结对编程时间紧密,在一定程度上可以督促双方学习,提高 ...
- mybaits拦截器+自定义注解
实现目的:为了存储了公共字典表主键的其他表在查询的时候不用关联查询(所以拦截位置位于mybaits语句查询得出结果集后) 项目环境 :springboot+mybaits 实现步骤:自定义注解——自定 ...
- ElasticSearch NEST笔记
ElasticSearch NEST笔记 1. 什么是ElasticSearch? ElasticSearch is a powerful open source search and analyti ...
- PAT 1033 旧键盘打字
https://pintia.cn/problem-sets/994805260223102976/problems/994805288530460672 旧键盘上坏了几个键,于是在敲一段文字的时候, ...