【bzoj 2870】 最长道路tree
边分治
边分和点分相比就是找到一条重心边,考虑所有经过这条边的路径,之后断开这条边分成两个联通块,继续分治
由于每次分治重心是一条边,所以只会产生两个联通块,考虑两个联通块显然要比像点分那样考虑多个联通块容易
但是边分有一个问题,就是遇到菊花图就自闭了,复杂度变成了\(O(n^2)\)
我们注意到边分的复杂度还和每个点的度数有关系,于是我们建一些虚点和虚边,把这棵树变成一棵二叉树,这样复杂度就是\(O(n\operatorname{logn})\)了
具体做法就是,一旦发现一个节点有多与两个儿子,就新建两个虚点,之后把这些儿子按照奇偶性分给两个儿子
对于这道题,虚点的点设成其父亲的点权,虚边的边权为\(0\),我们每次把两个联通块的内的路径拿出排序,双指针扫一扫拼一拼就好了
代码
#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=2e5+5;
struct E{int v,nxt,w;}e[maxn<<1];
int head[maxn],n,num,sum[maxn],vis[maxn];
int rn,S,top[2],Mnow,tax[maxn],rt,val[maxn];
struct Seg{int l,v;}st[2][maxn];
std::vector<int> son[maxn];LL ans;
inline int cmp(const Seg &A,const Seg &B) {return A.v<B.v;}
inline void add(int x,int y,int w) {
e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=w;
}
void dfs1(int x,int fa) {
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa) continue;
son[x].push_back(e[i].v);
dfs1(e[i].v,x);
}
}
void getrt(int x,int fa) {
sum[x]=1;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[i>>1]||e[i].v==fa) continue;
getrt(e[i].v,x);sum[x]+=sum[e[i].v];
int now=max(sum[e[i].v],S-sum[e[i].v]);
if(now<Mnow) Mnow=now,rt=i;
}
}
void dfs2(int o,int x,int fa,int l,int v) {
v=min(v,val[x]);st[o][++top[o]]=(Seg){l,v};
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa||vis[i>>1]) continue;
dfs2(o,e[i].v,x,l+e[i].w,v);
}
}
void solve(int x,int sz) {
Mnow=maxn;S=sz;getrt(x,0);
if(Mnow==maxn) return;
int now=rt;vis[rt>>1]=1;
top[0]=0;dfs2(0,e[now].v,0,0,maxn);
top[1]=0;dfs2(1,e[now^1].v,0,0,maxn);
std::sort(st[0]+1,st[0]+top[0]+1,cmp);
std::sort(st[1]+1,st[1]+top[1]+1,cmp);
tax[top[1]]=st[1][top[1]].l;int j=1;
for(re int i=top[1]-1;i;--i) tax[i]=max(st[1][i].l,tax[i+1]);
for(re int i=1;i<=top[0];i++) {
while(st[1][j].v<st[0][i].v&&j<=top[1]) j++;
if(j<=top[1]&&st[1][j].v>=st[0][i].v)
ans=max(ans,1ll*st[0][i].v*(e[now].w+st[0][i].l+tax[j]+1));
}
tax[top[0]]=st[0][top[0]].l;j=1;
for(re int i=top[0]-1;i;--i) tax[i]=max(st[0][i].l,tax[i+1]);
for(re int i=1;i<=top[1];i++) {
while(st[0][j].v<st[1][i].v&&j<=top[0]) j++;
if(j<=top[0]&&st[0][j].v>=st[1][i].v)
ans=max(ans,1ll*st[1][i].v*(e[now].w+st[1][i].l+tax[j]+1));
}
int ss=sz-sum[e[now].v];
solve(e[now].v,sum[e[now].v]);solve(e[now^1].v,ss);
}
int main() {
n=rn=read();
for(re int i=1;i<=n;i++) val[i]=read();
for(re int x,y,i=1;i<n;i++)
x=read(),y=read(),add(x,y,0),add(y,x,0);
dfs1(1,0);
num=1;memset(head,0,sizeof(head));
for(re int i=1;i<=n;i++) {
int sz=son[i].size();
if(!sz) continue;
if(sz==1) {
add(i,son[i][0],son[i][0]<=rn);
add(son[i][0],i,son[i][0]<=rn);
continue;
}
if(sz==2) {
add(i,son[i][0],son[i][0]<=rn);add(son[i][0],i,son[i][0]<=rn);
add(i,son[i][1],son[i][1]<=rn);add(son[i][1],i,son[i][1]<=rn);
continue;
}
int t1=++n,t2=++n;val[t1]=val[t2]=val[i];
add(i,t1,0),add(t1,i,0);add(i,t2,0),add(t2,i,0);
for(re int j=0;j<son[i].size();j++)
if(j&1) son[t1].push_back(son[i][j]);
else son[t2].push_back(son[i][j]);
}
solve(1,n);
std::cout<<ans;
}
【bzoj 2870】 最长道路tree的更多相关文章
- bzoj 2870 最长道路tree——边分治
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2870 关于边分治:https://www.cnblogs.com/Khada-Jhin/p/ ...
- BZOJ 2870: 最长道路tree 树的直径+并查集
挺好的一道题. 把所有点都离线下来,一个个往里加入就行了. #include <cstdio> #include <algorithm> #define N 100003 #d ...
- 2870: 最长道路tree
链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2870 思路 先把树转化为二叉树 再链分治 %%yyb 代码 #include <ios ...
- 【BZOJ2870】最长道路tree 点分治+树状数组
[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...
- BZOJ2870—最长道路tree
最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都 ...
- BZOJ2870: 最长道路tree
题解: 子树分治的做法可以戳这里:http://blog.csdn.net/iamzky/article/details/41120733 可是码量... 这里介绍另一种好写又快的方法. 我们还是一颗 ...
- bzoj2870最长道路tree——边分治
简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 有几个不同的做法: 1.sort+并查集+树的直径.边从大到小加入 ...
- 【bzoj2870】最长道路tree 树的直径+并查集
题目描述 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大. 其中链长度定义为链上点的个数. 输入 第一行N 第二行N个数分别表示1~N的点权v[i] 接下来N-1行每 ...
- BZOJ2870 最长道路tree(并查集+LCA)
题意 (n<=50000) 题解 #include<iostream> #include<cstring> #include<cstdio> #include ...
随机推荐
- SQL Server中配置ODBC数据源
单击“开始→windows系统→控制面板”,打开控制面板 单击“管理工具→ODBC数据源(32位)”打开ODBC数据源配置对话框 在数据源配置对话框中单击“系统DSN”选项卡下的“添加”按钮,创建数据 ...
- 更强大的实时数仓构建能力!分析型数据库PostgreSQL 6.0新特性解读
阿里云 AnalyticDB for PostgreSQL 为采用MPP架构的分布式集群数据库,完备支持SQL 2003,部分兼容Oracle语法,支持PL/SQL存储过程,触发器,支持标准数据库事务 ...
- javafx教程大全
链接: https://www.yiibai.com/javafx
- NX二次开发-UFUN获取对象的显示属性(图层,颜色,空白状态,线宽,字体,高亮状态)UF_OBJ_ask_display_properties
NX9+VS2012 #include <uf.h> #include <uf_modl.h> #include <uf_obj.h> UF_initialize( ...
- NX二次开发-UFUN修改当前导出CGM文件选项设置UF_CGM_set_session_export_options
文章转载自唐康林NX二次开发论坛,原文出处: http://www.nxopen.cn/thread-126-1-1.html 刚才有同学问到这个问题,如果是用NXOpen来做,直接录制一下就可以了: ...
- vmware压缩磁盘空间的方法, linux怎么卸载vmware
家里笔记本40G,可用空间怎么挤都只剩7G,从单位copy回来的linux虚拟机要10G,经检查实际使用空间5.7,也就是其他都是空余空间,可以释放掉.(只适合independent.Persiste ...
- springmvc静态资源;mvc:default-servlet-handler后Controller失效
springmvc静态资源;mvc:default-servlet-handler后Controller失效 web.xml配置<url-pattern>/</url-pattern ...
- KEIL, MDK 关于C99结构体变量初始化
C99:here 例如声明了这样的结构体 void test1() { tt_t t1 ={ .a = , .d = 'd', .b = , .c = }; static tt_t t2 = { ,, ...
- ElasticSearch 索引查询使用指南
1.检测集群是否健康,我们通常用下面的命令.确保9200端口号可用: http://localhost:9200/_cat/health?v 或者 http://localhost:9200/_clu ...
- 如果一个文件块有130M,请问有多少个mapper
如果一个文件块有130M,请问有多少个mapper 130M的文件将被分成2个mapper. 原因:根据FileInputFormat类 有一个成员变量 private static final do ...