zoukankan      html  css  js  c++  java
  • 【洛谷p3994】Highway 二分+斜率优化DP

    题目大意:给你一颗$n$个点的有根树,相邻两个点之间有距离,我们可以从$x$乘车到$x$的祖先,费用为$dis imes P[x]+Q[x]$,问你除根以外每个点到根的最小花费。

    数据范围:$n≤10^6$。

    此题我们显然$dp$,列出方程为$f[x]=min{f[y]+dis(x,y) imes P[x]+Q[x]}$,其中$y$为$x$的祖先。

    不难看出可能是一个斜率优化的式子,我们往下推推

    设$i$是$j$的祖先,且从$i$出转移比从$j$处转移劣,不难列出:

    $f[i]+dis(i,x)P[x]+Q[x]>f[j]+dis(j,x)P[x]+Q[x]$

    化简化简,令$D_i$表示从根到$i$的距离,继续移项化简

    $f[i]-f[j]>P[x]((D_x-D_j)-(D_x-D_i))$

    $f[i]-f[j]>P[x](D_i-D_j)$

    $dfrac{f[i]-f[j]}{D_i-D_j}<P[x]$(注意大于符号变成小于,因为$D_i<D_j$,重要!,我被坑了)

    考虑到$P$随着点深度递增,于是就可以快乐斜率优化了。

    不过这题需要在树上转移,当遍历完一个子树后,我们要把单调队列恢复,恢复操作显然可以用可持久化线段树来搞。

    其实不用这么复杂,考虑到只存在移动队头,移动队尾&在队尾加一个数的操作,我们只需要记录下以前的队头/尾的情况,还有被覆盖的数原先是啥,就可以在常数时间内恢复回去。

    然而这么做的话无法保证移动队头尾的次数是线性的(我们搞一个链+链底菊花树),所以在找队头和队尾时,需要用二分。

    于是时间复杂度就变成$O(nlog n)$了,二分的常数很小,问题不大。

    (我比较懒写了暴力移动的,二分的话自己脑补吧qwq)

     1 #include<bits/stdc++.h>
     2 #define M 1000005
     3 #define L long long
     4 using namespace std;
     5 
     6 struct edge{L u,v,next;}e[M]={0}; L head[M]={0},use=0;
     7 void add(L x,L y,L z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
     8 L n,f[M]={0},P[M]={0},Q[M]={0},dis[M]={0},q[M]={0},h=1,t=0;
     9 
    10 double slope(L i,L j){return 1.*(f[i]-f[j])/(dis[i]-dis[j]);}
    11 
    12 void dfs(L x,L D){
    13     L H=h,T=t;
    14     while(h<t&&P[x]>slope(q[h],q[h+1])) h++;
    15     f[x]=f[q[h]]+((dis[x]=D)-dis[q[h]])*P[x]+Q[x];
    16     while(h<t&&slope(q[t-1],q[t])>slope(q[t],x)) t--;
    17     L lastT=q[++t]; q[t]=x;
    18     for(L i=head[x];i;i=e[i].next) dfs(e[i].u,D+e[i].v);
    19     q[t]=lastT; h=H; t=T;
    20 }    
    21 
    22 main(){
    23     scanf("%lld",&n);
    24     for(L i=2;i<=n;i++){
    25         L fa,dis; scanf("%lld%lld%lld%lld",&fa,&dis,P+i,Q+i);
    26         add(fa,i,dis);
    27     }
    28     q[t=1]=1; for(L i=head[1];i;i=e[i].next) dfs(e[i].u,e[i].v);
    29     for(L i=2;i<=n;i++) printf("%lld
    ",f[i]);
    30 }
  • 相关阅读:
    安全相关小知识
    http小知识
    跨域资源共享 CORS
    Django——CRSF攻击及处理
    Django——XSS攻击及处理
    Django——模版层(前后端交互编码方式,django模板使用的两种方式,模板语法之变量&深度查询句点符,模板渲染成标签还是原字符串,过滤器+自定义,标签+自定义)
    Django——Postman介绍及安装, 测试项目
    Django——视图层(请求&响应对象,cbv和fbv,文件上传)
    一个http请求从浏览器发出去,经历的过程(即上网流程)
    Django——有名分组 无名分组,反向解析,名称空间
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10424208.html
Copyright © 2011-2022 走看看