bzoj 2870 最长道路tree——边分治
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2870
关于边分治:https://www.cnblogs.com/Khada-Jhin/p/10154994.html
自己写了那种把一个孩子连向自己,其他孩子连新建节点的重构图方法。
如果 vector 里最后一个元素恰好是父亲的话,末尾就会有一个新建节点只有一个孩子。
solve( ) 完之后要继续 get_rt( ) ,想知道两边的点数 ts ;可以发现 to[ cr ] 的部分点数恰好是 siz[ to[ cr ] ] ,另一部分就是 s - siz[ to[ cr ] ] 了。
要递归的时候,如果 ts == 1 ,就不递归了。
关于这道题:https://www.cnblogs.com/Miracevin/p/10430192.html
虚点的点权就是它建出它的那个实点的点权;路径上的点数等于路径上的实边条数 + 1 。
找出两边的路径,分别 sort 然后双指针即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}
const int N=5e4+,M=N<<,INF=7e4;
int n,vl[M],hd[M],xnt=,to[M<<],nxt[M<<],w[M<<];//xnt=1
int siz[M],mn,Rt,tot[]; bool vis[M]; ll ans;
vector<int> vt[N];
struct Node{
int dis,mn;
Node(int d=,int m=):dis(d),mn(m) {}
bool operator< (const Node &b)const
{return mn<b.mn;}
}a[][M];
void add(int x,int y,int z)
{
to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;
to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;w[xnt]=z;
}
void Rbuild(int cr,int fa)
{
for(int i=,lm=vt[cr].size()-,v,lst=;i<=lm;i++)
{
if((v=vt[cr][i])==fa)continue;
if(!lst) add(cr,v,), lst=cr;
else if(i==lm) add(lst,v,);
else
{
n++; vl[n]=vl[cr];
add(lst,n,); add(n,v,); lst=n;
}
}
for(int i=,lm=vt[cr].size(),v;i<lm;i++)
if((v=vt[cr][i])!=fa)Rbuild(v,cr);
}
void get_rt(int cr,int fa,int s)
{
siz[cr]=;
for(int i=hd[cr],v,d;i;i=nxt[i])
if(!vis[i>>]&&(v=to[i])!=fa)
{
get_rt(v,cr,s); siz[cr]+=siz[v];
d=Mx(siz[v],s-siz[v]);
if(d<mn)mn=d, Rt=i;
}
}
void dfs(int cr,int fa,int lj,int mn,bool fx)
{
mn=Mn(mn,vl[cr]); a[fx][++tot[fx]]=Node(lj,mn);
for(int i=hd[cr],v;i;i=nxt[i])
if(!vis[i>>]&&(v=to[i])!=fa)
dfs(v,cr,lj+w[i],mn,fx);
}
void cz()
{
for(int i=;i<=;i++)
sort(a[i]+,a[i]+tot[i]+);
int p0=tot[]+, lj=, tw=w[Rt]+;//+1
for(int i=tot[];i;i--)
{
int tmn=a[][i].mn;
while(p0>&&a[][p0-].mn>=tmn)
p0--, lj=Mx(lj,a[][p0].dis);
if(p0>tot[])continue;//
ans=Mx(ans,(ll)tmn*(lj+a[][i].dis+tw));
}
p0=tot[]+; lj=;
for(int i=tot[];i;i--)
{
int tmn=a[][i].mn;
while(p0>&&a[][p0-].mn>=tmn)
p0--, lj=Mx(lj,a[][p0].dis);
if(p0>tot[])continue;//
ans=Mx(ans,(ll)tmn*(lj+a[][i].dis+tw));
}
}
void solve(int cr,int s)
{
vis[cr>>]=;
tot[]=tot[]=;
dfs(to[cr],,,INF,); dfs(to[cr^],,,INF,);
cz();
int v=to[cr], ts=siz[v];
if(ts>){mn=N; get_rt(v,,ts); solve(Rt,ts);}
ts=s-ts; v=to[cr^];// s-ts not s-siz[v] for siz[v] may changed!!!
if(ts>){mn=N; get_rt(v,,ts); solve(Rt,ts);}
}
int main()
{
n=rdn();
for(int i=;i<=n;i++)vl[i]=rdn();
for(int i=,u,v;i<n;i++)
{
u=rdn();v=rdn(); vt[u].pb(v); vt[v].pb(u);
}
Rbuild(,);
mn=N;get_rt(,,n);solve(Rt,n);
printf("%lld\n",ans);
return ;
}
bzoj 2870 最长道路tree——边分治的更多相关文章
- BZOJ 2870: 最长道路tree 树的直径+并查集
挺好的一道题. 把所有点都离线下来,一个个往里加入就行了. #include <cstdio> #include <algorithm> #define N 100003 #d ...
- 【BZOJ2870】最长道路tree 点分治+树状数组
[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...
- bzoj2870最长道路tree——边分治
简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 有几个不同的做法: 1.sort+并查集+树的直径.边从大到小加入 ...
- 2870: 最长道路tree
链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2870 思路 先把树转化为二叉树 再链分治 %%yyb 代码 #include <ios ...
- 【BZOJ2870】最长道路(边分治)
[BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...
- BZOJ2870—最长道路tree
最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都 ...
- 【bzoj 2870】 最长道路tree
题目 边分治 边分和点分相比就是找到一条重心边,考虑所有经过这条边的路径,之后断开这条边分成两个联通块,继续分治 由于每次分治重心是一条边,所以只会产生两个联通块,考虑两个联通块显然要比像点分那样考虑 ...
- [BZOJ2870]最长道路tree:点分治
算法一:点分治+线段树 分析 说是线段树,但是其实要写树状数组卡常. 代码 #include <bits/stdc++.h> #define rin(i,a,b) for(register ...
- BZOJ2870: 最长道路tree
题解: 子树分治的做法可以戳这里:http://blog.csdn.net/iamzky/article/details/41120733 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...
随机推荐
- 20165326 java第六周学习笔记
第六周学习总结 ch8 String类对于有效处理字符序列信息非常重要. String对象的字符序列不能被修改删除,无法发生变化. StringBuffer类的对象实体的内存空间可以自动改变大小,便于 ...
- 20165214 学习基础与C语言基础调查
读后感 我花时间仔细阅读了娄老师公众号上的那5篇关于自己各个方面学习经历的文章,随后深为震撼又自愧不如. 我实在没想到,这套学习方法竟有如此巨大的力量!纵使在娄老师不熟悉的乒乓球领域,娄老师也能通过这 ...
- L255 Learning to say no brings a thrill of freedom
I am not sure who came up with that thing about never saying yes to something in the distant future ...
- L253 Work and Pleasure
To be really happy and really safe, one ought to have at least two or three hobbies, and they must a ...
- Codex Delphi Expert
https://www.delphiworlds.com/codex/?tdsourcetag=s_pcqq_aiomsg Codex是什么? 是一个可以安装到Delphi IDE中的专家 有助于提高 ...
- mysql创建用户并授予权限
MySQL创建数据库与创建用户以及授权 1.create schema [数据库名称] default character set utf8 collate utf8_general_ci;--创 ...
- Linux运维命令总结(-)
Linux运维命令总结(-) 此次整理linux运维常用命令13个,常用linux运维命令大概有150个,约占百分之十,大牛见笑,本人菜鸟一枚不才整理如下,如有不正确之处,请多多指正. 1.创建目录 ...
- 【Python】创建xml文档
#练习:创建xml文档 import xml.dom.minidom import codecs #在内存中创建一个空的文档 doc = xml.dom.minidom.Document() ...
- MySQL 显示表字段及注释等信息
SHOW TABLES from resource [FROM db_name] //列出数据库数据表 SHOW TABLE STATUS from resource [FROM db_name] ...
- linux 将一个文件分解成多个不同名文件
1.通过c直接实现 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include & ...