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是新插入 ...
随机推荐
- Nginx报错: "Too many open files accept" 和 "could not build the server_names_hash"
一.访问Nginx时,报错:"accept() failed (24: Too many open files)"原因时:nginx的连接数超过了系统设定的最大值造成的. 处理办法 ...
- 保留最新N份备份目录脚本
如下所示,在/opt/backup下是备份目录,只需要保留最新的三份备份,在此之前的备份目录都要删除. [root@syslog-ng ~]# cd /opt/backup/ [root@syslog ...
- sheet制作返回按钮
=HYPERLINK("#目录!A1","目录!A1") =HYPERLINK("#"&A2&"!A1" ...
- Python学习笔记 -- 第六章 文件操作
I/O编程 在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这 ...
- 续摄影O2O篇
项目名:摄影O2O 工具:Eclipse ,adt,jdk1.8,MySQL 步骤:(一) 1.导入beauty项目到一个adt中,然后创建模拟器,运行(客户端) 2.导入SocketSever项目到 ...
- 四则运算APP
1) N (Need 需求) 用户基本需求:随机生成四则运算,能自动判定对错,答错时能提示正确答案! 在这个基础上,我的创意: 多用户模式,能记录用户的答题情况(登陆功能) 分级挑战,按照不同的水 ...
- 作业二 —— 分布式版本控制系统Git的安装与使用
作业要求源于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 1.安装Git,配置用户名与邮箱. 安装Windows版的Git ...
- Maven -Maven配置tomcat插件 两种
Maven Tomcat插件现在主要有两个版本,tomcat-maven-plugin和tomcat7-maven-plugin,使用方式基本相同. tomcat-maven-plugin 插件官网: ...
- HDU 2029 Palindromes _easy version
http://acm.hdu.edu.cn/showproblem.php?pid=2029 Problem Description “回文串”是一个正读和反读都一样的字符串,比如“level”或者“ ...
- 通过反射来读取XML格式的ControlTemplate
在之前的一个WPF项目中,由于设置控件模板在前台xaml中读取失败,由此想到了通过反射的形式来读取该模板,首先将该模板写入一个xml文件中,然后再读取该xml文件,在这里首先介绍一下:资源和嵌入式资源 ...