zoukankan      html  css  js  c++  java
  • Lost My Music:倍增实现可持久化单调栈维护凸包

    题目就是求树上每个节点的所有祖先中(ci-cj)/(dj-di)的最小值。

    那么就是(ci-cj)/(di-dj)的最大值了。

    对于每一个点,它的(ci,di)都是二维坐标系里的一个点

    要求的就是祖先节点的所有点与目前节点连线的最小斜率

    比较容易想到单调栈优化,像斜率优化dp一样

    但是关键是本题在树上,会有很多麻烦的操作。

    当搜到某一个儿子时可能会弹很多栈,而回溯的过程中需要把它们加回来。

    如果暴力执行的话,会在蒲公英图退化为n2

    考虑优化:现在的关键就是在于在一个元素可能被弹栈/还原多次的情况下如何快速维护?

    考虑倍增。st[i][j]表示从j的代表元素在栈里向前跳2i个元素后的代表元素是谁。我们可以对于每一个节点都开一个log级别的栈。

    那么只需要探讨要把某一个元素接在父亲栈里的哪一个位置就好了。单调栈当然满足单调性,故可以倍增跳跃。

    那么对于父亲节点的栈其实我们并不改变它。

    一个元素因为可能弹栈所以后端的元素可能不唯一,但是入栈时间确定那么前面的元素就唯一确定。

    单调栈顶就是最优决策点。

    研究代码,很好理解。

     1 #include<cstdio>
     2 int st[22][500005],fir[500005],l[500005],to[500005],cnt,n,c[500005];
     3 int q[500005],fa[500005],dep[500005];long double ans[500005];
     4 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
     5 long double calc(int x,int y){return 1.0L*(c[x]-c[y])/(dep[y]-dep[x]);}
     6 void pop_push(int p){
     7     int x=fa[p];
     8     for(int i=20;i>=0;--i)if(st[0][st[i][x]]&&calc(st[0][st[i][x]],st[i][x])<calc(st[i][x],p))x=st[0][st[i][x]];
     9     if(st[0][x]&&calc(st[0][x],x)<calc(x,p))x=st[0][x];
    10     st[0][p]=x;ans[p]=calc(st[0][p],p);
    11     for(int i=1;i<=20;++i)st[i][p]=st[i-1][st[i-1][p]];
    12 }
    13 int main(){
    14     scanf("%d",&n);q[1]=1;
    15     for(int i=1;i<=n;++i)scanf("%d",&c[i]);
    16     for(int i=2;i<=n;++i)scanf("%d",&fa[i]),link(fa[i],i);
    17     for(int h=1,t=1;h<=t;++h){
    18         dep[q[h]]=dep[fa[q[h]]]+1;pop_push(q[h]);
    19         for(int i=fir[q[h]];i;i=l[i])q[++t]=to[i];
    20     }
    21     for(int i=2;i<=n;++i)printf("%.8Lf
    ",ans[i]);
    22 }
    View Code
  • 相关阅读:
    Android ImageView设置图片原理(下)
    C++ 虚函数表 多重继承
    C++ 虚函数表 单继承
    私有继承
    内联函数和宏定义的区别
    #pragma pack(x) CPU对齐
    static 变量(静态变量)
    C++ 中const作用
    如何连接宏参数
    几种常见容器比较和分析 hashmap, map, vector, list ...hash table
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11371320.html
Copyright © 2011-2022 走看看