博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj2870最长道路tree——边分治
阅读量:4957 次
发布时间:2019-06-12

本文共 2641 字,大约阅读时间需要 8 分钟。

简化版描述:

给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积最大。
其中链长度定义为链上点的个数。
 

有几个不同的做法:

1.sort+并查集+树的直径。边从大到小加入,并查集维护连通块,记录连通块的直径的两个端点,合并连通块的时候更新直径,并且用len*bian[i].w更新答案

  有排序,O(nlogn)

2.点分治+树状数组。点分治路径合并的时候挺恶心。先都扫一遍所有子树,把路径最小值作为下标,链长作为权值放进树状数组里。

  再枚举子树搜一遍,先减去当前子树的贡献,再搜的时候从树状数组找后缀最大值。思想就是钦定最小值在当前子树的某个路径中

  O(nlog^2)

3.点分治

  把过重心的子树分成两堆递归?不懂。。。O(nlogn)

  代码太长,还不如写边分治

4.边分治

 本身其实点分治还可以暴力枚举重心子树的所有兄弟然后双指针,从而不用树状数组,但是复杂度是O(度数^2nlogn)的。不优秀

边分治就两个儿子自然好办啦

三度化然后边分治,两个子树的路径存进两个数组,按照最小值sort,然后倒序枚举双指针。记录最小值不小于当前钦定子树的最大的深度,左右各做一遍即可

过虚点其实一定过了x,所以虚点权值定为x的权值。

虚边的权值就是0,实边是1,两点链长是深度+1

 

代码:

注意,如果对面的儿子没有选择一个点,那么不能计算当前的中心边的权值

 

#include
#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=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x);}namespace Miracle{const int N=200000+5;const int inf=0x3f3f3f3f;int n;int tot;int val[N];struct node{ int nxt,to; int w;}e[2*N],bian[2*N];int cnt1=1,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=0; for(reg i=pre[x];i;i=bian[i].nxt){ int y=bian[i].to; if(y==fa) continue; if(!ff){ add(x,y,1); add(y,x,1); ff=x; }else{ int tmp=++tot; val[tmp]=val[x]; add(ff,tmp,0);add(tmp,ff,0); add(tmp,y,1);add(y,tmp,1); ff=tmp; } rebuild(y,x); }}pair
ls[N],rs[N];int lsc,rsc;bool cmp(pair
A,pair
B){ if(A.fi==B.fi) return A.se
=1;--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+1)*ls[i].fi); } mxdep=0;ptr=lsc; for(reg i=rsc;i>=1;--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+1)*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=1;i<=n;++i) rd(val[i]),ans=max(ans,(ll)val[i]); int x,y; for(reg i=1;i

 

转载于:https://www.cnblogs.com/Miracevin/p/10430192.html

你可能感兴趣的文章
iTextSharp带中文转换出来的PDF文档显示乱码
查看>>
阶乘因式分解(一)
查看>>
qt学习记录-----3.信号与槽的问题
查看>>
『ORACLE』 内置约束(11g)
查看>>
Vue--学习过程中遇到的坑
查看>>
组件:slot插槽
查看>>
.net压缩图片质量(附demo)
查看>>
equals和==的区别
查看>>
Android6.0指纹识别开发
查看>>
java反射机制剖析(二)— Class Loader
查看>>
走进C++程序世界------异常处理
查看>>
通过用户模型,对数据库进行增删改查操作。
查看>>
去除数组中重复的元素
查看>>
Nginx配置文件nginx.conf中文详解(转)
查看>>
POJ 1988 Cube Stacking
查看>>
POJ 1308 Is It A Tree?(并查集)
查看>>
N进制到M进制的转换问题
查看>>
Android------三种监听OnTouchListener、OnLongClickListener同时实现即其中返回值true或者false的含义...
查看>>
MATLAB实现多元线性回归预测
查看>>
Mac xcode 配置OpenGL
查看>>