题目: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——边分治的更多相关文章

  1. BZOJ 2870: 最长道路tree 树的直径+并查集

    挺好的一道题. 把所有点都离线下来,一个个往里加入就行了. #include <cstdio> #include <algorithm> #define N 100003 #d ...

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

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

  3. bzoj2870最长道路tree——边分治

    简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数.   有几个不同的做法: 1.sort+并查集+树的直径.边从大到小加入 ...

  4. 2870: 最长道路tree

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2870 思路 先把树转化为二叉树 再链分治 %%yyb 代码 #include <ios ...

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

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

  6. BZOJ2870—最长道路tree

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

  7. 【bzoj 2870】 最长道路tree

    题目 边分治 边分和点分相比就是找到一条重心边,考虑所有经过这条边的路径,之后断开这条边分成两个联通块,继续分治 由于每次分治重心是一条边,所以只会产生两个联通块,考虑两个联通块显然要比像点分那样考虑 ...

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

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

  9. BZOJ2870: 最长道路tree

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

随机推荐

  1. github 多人协作

    1.本地生成私钥: ssh-keygen -C "YourEmail@example.com" (这里的email使用github账号)生成公钥和私钥 2.查看私钥,并添加到自己的 ...

  2. react native 之 Android物理返回键

    基本用法 根据文档,安卓back键的处理主要就是一个事件监听: BackAndroid.addEventListener('hardwareBackPress', this.onBackPressed ...

  3. es6 常用总结

    1.变量 let 声明的变量只在它所在的代码块有效,不允许重复声明 const 声明是一个只读的常量.一旦声明,常量的值就不能改变. const与let的作用域相同,只在声明所在的块级作用域内有效. ...

  4. 清除chrome浏览器HSTS缓存

    如果你的网站启用了HSTS 在chrome中会用缓存效果,即使你的站点取消了HSTS,下次访问时,仍旧会自动给你重定向到HSTS. 那么如何清除 HSTS呢? chrome://net-interna ...

  5. 20165228 学习基础和C语言基础调查

    ========== 做中学读后感 我依然认为兴趣与自觉性是推动一个人进步的两大因素,他们之间的区别是"兴趣"带来的影响更多是主动性的学习,而"自觉"则是略显被 ...

  6. 餐巾计划问题 zwk费用流解法

    «问题描述:一个餐厅在相继的N 天里,每天需用的餐巾数不尽相同.假设第i天需要ri块餐巾(i=1,2,…,N).餐厅可以购买新的餐巾,每块餐巾的费用为p分:或者把旧餐巾送到快洗部,洗一块需m天,其费用 ...

  7. Educational Codeforces Round 54 ---1076ABCDE

    1076A---Minimizing the String[字符串] http://codeforces.com/contest/1076/problem/A 题意: 删掉字符串中的一个字符使得得到的 ...

  8. webpack的一些详细配置

    http://blog.csdn.net/c_kite/article/details/71279853

  9. Nginx访问日志、 Nginx日志切割、静态文件不记录日志和过期时间

    1.Nginx访问日志 配制访问日志:默认定义格式: log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_loc ...

  10. C# 用反射动态绑定事件

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...