P4292 【[WC2010]重建计划】
P4292 【[WC2010]重建计划】
长链剖分
分数规划和长链剖分大体思路大佬们已经讲得很清楚了
奈何我太蒟了被有个问题卡了我很久
就是怎么分配每个子树对应的线段树的空间
当我们正在处理 x 点时
先递归处理完它的重儿子也就是 y
然后直接让 x 继承 y 的数据
若 y 对应的数组长这样子
我们发现在 y 这棵树中
x 为距离 1 的点就是 y 距离 0 的点
x 为距离 2 的点就是 y 距离 1 的点…
所以这个显然就是
我们先遍历重儿子所形成的 dfs 序
其中每一条长链都对应的一段区间
所以这道题就是对 dfs 序建一颗线段树
x子树中 距离为n的点的最大权值
对应的是线段树中第 dfn[x]+n 个元素
我也搞不懂为什么我在这种显zhi然zhang的地方卡这么久
最外层的二分一个log 线段树一个log
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
最后代码
#include <bits/stdc++.h>
#define N 100100
#define M 200100
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
const double inf=-5e11*1.0;
int n,minn,maxx;
int f[N],nxt[M],data[M],num;
int dfn[N],mdep[N],dep[N],son[N],fa[N],len[N],root,ti;
double rr,mm,lst[N],far[M],dis[N];
int posi[N];
bool ans;
struct _tr{
double t[N<<3];
inline void push_up(int rt){
t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
inline void updata(int pos,double c,int rt=1,int l=1,int r=n){
if(l==r){ t[rt]=max(c,t[rt]); return; }
if(pos<=mid){ updata(pos,c,lson); }
else{ updata(pos,c,rson); }
push_up(rt);
}
inline double query(int L,int R,int rt=1,int l=1,int r=n){
if(L<=l&&r<=R)return t[rt];
double res=inf;
if(L<=mid)res=max(res,query(L,R,lson));
if(R>mid)res=max(res,query(L,R,rson));
return res;
}
inline void build(int rt=1,int l=1,int r=n){
t[rt]=inf;
if(l==r){ posi[l]=rt; return; }
build(lson); build(rson);
}
}q;
void inline add(int x,int y,int z){
nxt[++num]=f[x]; f[x]=num; data[num]=y; far[num]=z;
}
inline void dfs(int x){
int y;
for(int i=f[x];i;i=nxt[i]){
y=data[i]; if(y==fa[x])continue;
lst[y]=far[i];
fa[y]=x; dep[y]=mdep[y]=dep[x]+1; dfs(y);
if(mdep[x]<mdep[y]){
son[x]=y; mdep[x]=mdep[y];
}
}
len[x]=mdep[x]-dep[x];
}
inline void dfs2(int x){
dfn[x]=++ti;
if(son[x]){ dfs2(son[x]); }
int y;
for(int i=f[x];i;i=nxt[i]){
y=data[i]; if(y==fa[x]||y==son[x])continue;
dfs2(y);
}
}
inline void solve(int x){
int y=son[x],o=dfn[x],ql,qr,oo;
double z;
q.updata(o,dis[x]);
if(y){
dis[y]=dis[x]+lst[y]-mm;
solve(y); if(ans==1)return;
}
for(int i=f[x];i;i=nxt[i]){
y=data[i]; if(y==fa[x]||y==son[x])continue;
dis[y]=dis[x]+lst[y]-mm; solve(y); if(ans==1)return;
oo=dfn[y];
for(int j=0;j<=min(maxx,len[y]);j++){
ql=max(minn-1-j,0),qr=min(maxx-1-j,len[x]);
if(ql>qr)continue;
z=q.t[posi[oo+j]]-dis[x];
if(q.query(o+ql,o+qr)-dis[x]+z>=0){
ans=1; return;
}
}
for(int j=0;j<=min(len[y],maxx);j++){
ql=1+j;
if(q.t[posi[oo+j]]>q.t[posi[o+ql]]){ q.updata(o+ql,q.t[posi[oo+j]]); }
}
}
if(len[x]>=minn){
if(q.query(o+minn,o+min(len[x],maxx))>=dis[x]){
ans=1; return;
}
}
}
void get_ans(){
double l=0,r=rr;
while(r-l>0.0002){
mm=(l+r)/2.0000;
ans=0; dis[root]=0; q.build();
solve(root);
if(ans){ l=mm; }
else{ r=mm; }
}
printf("%.3lf",l);
}
int main(){
// freopen("test.in","r",stdin);
scanf("%d %d %d",&n,&minn,&maxx);
int u,v,z;
for(int i=1;i<n;i++){
scanf("%d %d %d",&u,&v,&z);
add(u,v,z); add(v,u,z);
rr=max((double)z,rr);
}
root=rand()%n+1;
dfs(root);
dfs2(root);
get_ans();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?