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 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...
随机推荐
- BSTR 转 char*
#include <comdef.h> #include <comutil.h> #pragma comment(lib,"comsuppw.lib") _ ...
- web 架构 /http协议,状态码,django中常用命令
什么是web应用? web应用 架构 :B/S架构 | C/S架构 网站:BS架构其实就是应用程序: B是浏览器 S是sever(实现了wsgi协议,实现了socket的服务端) + applicat ...
- IDEA发布应用时发布到lib下面的包不全
IDEA发布应用时发布到lib下面的包不全,Tomcate启动时就报:At least one JAR was scanned for TLDs yet contained no TLDs. Enab ...
- Linux命令--2
1 mkdir 命令 mkdir 命令用来创建指定名称的目录,要求创建目录的用户在当前目录中具有写权限,并且指定的目录名不能是当前目录中已有的目录. (1)命令格式 mkdir [选项] 目录 (2) ...
- python 基础 内置函数 和lambda表达式
1.把任意数值转化为字符串有两种方法. (1)str()用于将数值转化为易于人读的形式.print(str("我是中国人"))>>>我是中国人 (2)repr() ...
- [转]C++智能指针简单剖析
C++智能指针简单剖析 https://www.cnblogs.com/lanxuezaipiao/p/4132096.html 导读 最近在补看<C++ Primer Plus>第六版 ...
- PL/SQL程序设计、流程控制
PL/SQL是 Procedure Language & Structured Query Language 的缩写 PL/SQL是对SQL语言存储过程语言的扩展 PL/SQL程序由三个块组成 ...
- 1.4 Chrome浏览器
1.4 Chrome浏览器 前言selenium2启动Chrome浏览器是需要安装驱动包的,但是不同的Chrome浏览器版本号,对应的驱动文件版本号又不一样,如果版本号不匹配,是没法启动起来的. ## ...
- jupyter notebook远程服务器终端连接
如下图
- TJU Problem 2548 Celebrity jeopardy
下次不要被长题目吓到,其实不一定难. 先看输入输出,再揣测题意. 原文: 2548. Celebrity jeopardy Time Limit: 1.0 Seconds Memory Lim ...