题目大意:

求长度$\in [L,U]$的路径的最大边权和平均值。

题解

首先二分就不用说了,分数规划大家都懂。

这题有非常显然的点分治做法,但还是借着这个题学一波长链剖分。

其长链剖分本身也没啥,就是重链剖分中判断中儿子的参数由比较子树大小改为了子树最深点的深度。

这样一来,有一个很显然的性质,所有长链长度值和$<n$,然而这是废话,因为整棵树的边也只有$n-1$条。

长链剖分还有一个非常强大的能力,可以在线性的时间内合并以深度为下标的子树信息。

对于节点$x$和其长链连向的儿子$y$,由于在$Dfs$序中$x$就在$y$左边且挨着,所以不用合并,由于要合并的信息恰好以深度为下标,所以直接让$x$“继承”$y$的信息即可,接着考虑将其他儿子合并到$x$上。

对于任意其他的儿子$z$,我们直接暴力将它们合并即可,就是枚举每个$z$的每个深度,将它插入$x$处的数组中。所有点被暴力插入的复杂度是每一个不在父节点的长链上的点所在的长链的长度$=$所有长链的长度$=O(n)$。

换作这道题有什么用呢,假设每一个点$x$维护一个从$x$出发向下走到深度$D$的权值最大的链,就可以把它存在$Dfs$序的数组上,因为这恰是一个以深度为下标并且容易合并的东西。至于更新答案,只需要对于每一次暴力插入信息时,枚举深度的同时用线段树在当前$x$所占有的区间上查询一下即可。

还有一个小技巧,对于$lca(x,y)=m,len(x,y)=Dis[x]+Dis[y]-2\times Dis[m]$,其中$Dis[x]$表示按照当前二分的结果$x$到一号点的距离(不是深度),只需要维护$Dis[x]$即可,这样就避免了因为枚举的$m$不断往上走产生的大量区间修改操作。

于是最终复杂度为$O(n\cdot \log n \cdot\log V)$。

当然这道题应该还可以通过预处理和单调队列来达到$O(n\cdot \log n+n\cdot\log V)$。

然而我不会......

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
#define INF 4000000000000000ll
#define mid ((l+r)>>1)
using namespace std;
LL read(){
LL nm=0,fh=1; char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
LL n,m,L,R,ans,U,D,mxd[M],mxs[M],dfn[M],last[M],dst[M];
LL fs[M],nt[M<<1],to[M<<1],len[M<<1],cnt,tmp,res,S[M];
LL dis[M],p[M<<2],dep[M];
bool cmp(LL x,LL y){return mxd[x]<mxd[y];}
void link(LL x,LL y,LL dt){nt[tmp]=fs[x],fs[x]=tmp,len[tmp]=dt,to[tmp++]=y;}
void dfs1(LL x,LL last){
mxd[x]=dep[x];
for(LL i=fs[x];i!=-1;i=nt[i]){
if(to[i]==last) continue;
dep[to[i]]=dep[x]+1,dst[to[i]]=dst[x]+len[i],dfs1(to[i],x);
if(mxd[to[i]]>mxd[x]) mxd[x]=mxd[to[i]],mxs[x]=to[i];
}
}
void dfs2(LL x,LL last){
dfn[x]=++cnt; if(mxs[x]) dfs2(mxs[x],x);else return;
for(LL i=fs[x];i!=-1;i=nt[i]) if(to[i]!=last&&to[i]!=mxs[x]) dfs2(to[i],x);
}
void ins(LL x,LL l,LL r,LL pos,LL num){
p[x]=max(p[x],num); if(l==r) return;
if(pos<=mid) ins(x<<1,l,mid,pos,num);
else ins(x<<1|1,mid+1,r,pos,num);
}
LL query(LL x,LL l,LL r,LL ls,LL rs){
if(r<ls||rs<l||rs<ls) return -INF;
if(ls<=l&&r<=rs) return p[x];
return max(query(x<<1,l,mid,ls,rs),query(x<<1|1,mid+1,r,ls,rs));
}
void DP(LL x,LL last){
dis[x]=dst[x]-m*(dep[x]-1),ins(1,1,n,dfn[x],dis[x]);
if(!mxs[x]) return; DP(mxs[x],x);
for(LL i=fs[x];i!=-1;i=nt[i]){
if(to[i]==mxs[x]||to[i]==last) continue; DP(to[i],x);
if(ans>=0) return;
for(LL pos=0;pos+dep[to[i]]<=mxd[to[i]];pos++){
LL t1=D-pos-1,t2=min(U-pos-1,mxd[x]-dep[x]);
S[pos]=query(1,1,n,dfn[to[i]]+pos,dfn[to[i]]+pos);
ans=max(ans,query(1,1,n,dfn[x]+t1,dfn[x]+t2)+S[pos]-(dis[x]*2));
if(ans>=0) return;
}
for(LL pos=0;pos+dep[to[i]]<=mxd[to[i]];pos++){
ins(1,1,n,dfn[x]+pos+1,S[pos]);
}
}
ans=max(ans,query(1,1,n,dfn[x]+D,dfn[x]+min(U,mxd[x]-dep[x]))-dis[x]);
}
int main(){
n=read(),D=read(),U=read(),memset(fs,-1,sizeof(fs));
for(LL i=1;i<n;i++){
LL u=read(),v=read(),dt=read();
dt*=2000ll,link(u,v,dt),link(v,u,dt);
}
dep[1]=1,dfs1(1,0),dfs2(1,0);
for(L=0,R=2000000000ll;L<=R;){
for(LL i=1;i<=(n<<2);i++) p[i]=-INF;
m=((R>>1)+(L>>1)+(L&R&1)); ans=-1,DP(1,0);
if(ans<0) R=m-1; else res=m,L=m+1;
}
if(res&1) res++; res>>=1;
printf("%lld.%03lld\n",res/1000,res%1000); return 0;
}

WC2010 BZOJ1758 重建计划_长链剖分的更多相关文章

  1. [WC2010]重建计划(长链剖分版)

    传送门 Description Solution 时隔多年,补上了这题的长链剖分写法 感觉比点分治要好写的多 我们假设\(pos\)是当前点的\(dfn\),它距离所在链的底端的边的数量是\(len\ ...

  2. [WC2010]重建计划(长链剖分+线段树+分数规划)

    看到平均值一眼分数规划,二分答案mid,边权变为w[i]-mid,看是否有长度在[L,R]的正权路径.设f[i][j]表示以i为根向下j步最长路径,用长链剖分可以优化到O(1),查询答案线段树即可,复 ...

  3. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

  4. P4292-[WC2010]重建计划【长链剖分,线段树,0/1分数规划】

    正题 题目链接:https://www.luogu.com.cn/problem/P4292 题目大意 给出\(n\)个点的一棵树,然后求长度在\([L,U]\)之间的一条路径的平均权值最大. 解题思 ...

  5. [WC2010][BZOJ1758]重建计划-[二分+分数规划+点分治]

    Description 传送门 Solution 看到那个式子,显然想到分数规划...(不然好难呢) 然后二分答案,则每条边的权值设为g(e)-ans.最后要让路径长度在[L,U]范围内的路径权值&g ...

  6. BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP

    题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...

  7. 2019.01.21 bzoj1758: [Wc2010]重建计划(01分数规划+长链剖分+线段树)

    传送门 长链剖分好题. 题意简述:给一棵树,问边数在[L,R][L,R][L,R]之间的路径权值和与边数之比的最大值. 思路: 用脚指头想都知道要01分数规划. 考虑怎么checkcheckcheck ...

  8. [WC2010]重建计划 长链剖分

    [WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...

  9. 「WC2010」重建计划(长链剖分/点分治)

    「WC2010」重建计划(长链剖分/点分治) 题目描述 有一棵大小为 \(n\) 的树,给定 \(L, R\) ,要求找到一条长度在 \([L, R]\) 的路径,并且路径上边权的平均值最大 \(1 ...

随机推荐

  1. PHPstorm如何导入字体主题

    概要: 今天在安装phpstorm的时候发现导入字体主题时,出了问题,这个问题总是困惑我,并且曾经遇到过,没记录下来,所以想着这次记录下来吧.网上搜的稀里糊涂的,还是自己做个summary! 前提: ...

  2. 解决QT:forward declaration of &#39;struct Ui::xxx&#39;;invalid use of incomplete struct &quot;Ui::Widget&quot; 等莫名奇异错误

    今天在进行QT Widget的UI设计时,改了下Widget的对象名,然后在多次成功编译执行后,执行清理,又一次构建,就出现了好多莫名奇异的错误: widget.h:12: 错误:forward de ...

  3. XML使用总结(一)

    XML使用总结(一): XML是一种可拓展的标记语言,被设计用来描写叙述.存储及传递数据的语言体,而它的标签没有被提前定义,须要用户自行定义,是W3C推荐的数据存储和传递的标准标记语言. ·      ...

  4. 浅谈<持续集成、持续交付、持续部署>(二)

    集成是指软件个人研发的部分向软件整体部分交付,以便尽早发现个人开发部分的问题:部署是代码尽快向可运行的开发/测试节交付,以便尽早测试:交付是指研发尽快向客户交付,以便尽早发现生产环境中存在的问题.如果 ...

  5. 九度OJ 1356:孩子们的游戏(圆圈中最后剩下的数) (约瑟夫环)

    时间限制:10 秒 内存限制:32 兆 特殊判题:否 提交:1333 解决:483 题目描述: 每年六一儿童节,JOBDU都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为JOBDU的资深 ...

  6. phpstorm10激活方法

    选择 license server ---> http://idea.lanyus.com/   (末尾的斜杠不能漏了!) 2016-7-5更新 上面的注册方法再试时,已被封杀 2017-9-1 ...

  7. Symfony 使用KnpTimeBundle

    使用time_diff时出现:diff.ago.hour; 解决:1:引入"knplabs/knp-time-bundle": "^1.7",https://g ...

  8. jQuery 中的 Deferred 和 Promises(转)

    转自:http://www.css88.com/archives/4750/comment-page-1 看前首先了解:Promises/A规范,具体可以看这里,http://www.css88.co ...

  9. iOS 屏幕原点坐标 && 导航栏风格的自定义

    其一 屏幕原点坐标 (x ,y) 受 self.navigationController. navigationBar 的 setTranslucent (BOOL) 属性控制 在 iOS7 以后   ...

  10. Luogu-4410 [HNOI2009]无归岛

    裸的仙人掌最大独立子集,结果一个zz的错误让我调了好久... \(-inf\)开始设为\(0x7fffffff\)结果\(A_i\)有负数一加就炸了 #include<cstdio> #i ...