• 斜率优化之李超线段树


    三对于斜率优化,分为三种类型,一是斜率单调,第二种是是斜率不单调可以二分,第三种便是毫无规律可言的斜率情况,采用李超线段树可以在log范围内快速查询与修改,且能够胜任全部情况,代码与时间复杂度都很优秀。

    一,将每个dp[i]的状态看做一条直线,提取转化成具有固定的截距,斜率的式子

    二,查询操作来寻找当前决策最优的函数值

    方法为在值域内带入当前xi,取函数值的最优

    f为计算函数值函数 i是离散化之后的x坐标,c[i]为该离散化坐标,t为直线编号,x[t]为其固定斜率,y[t]为其固定截距

    1. double f(int i,int t)
    2. {
    3. return y[t]+x[t]*c[i];
    4. }

    李超线段树k维护的是当前x轴区域线段编号,l,r为离散化之后x坐标的范围,s[k]是当前x的最优决策线段

    每次我们查询当前决策最优的情况时,带入u=当前x,逐一定位u的精确范围,然后回溯答案。

    1. double qry(int k,int l,int r)
    2. {
    3. if(l==r)
    4. return f(u,s[k]);
    5. int m=(l+r)>>1;
    6. return max(f(u,s[k]),u>m?qry(k<<1|1,m+1,r):qry(k<<1,l,m));
    7. }

    三,插入直线操作

    插入直线操作就是将原本最优决策点替换的操作

    每次我们取一段线段的中间值,如果新直线在中点处函数值大于旧直线,那么就交换决策点。

    然后朝着使新直线更优的一侧进行递归,直到到达一个点时,再次比对函数值即可 

    1. void upd(int k,int t,int l,int r)
    2. {
    3. if(l==r)
    4. {
    5. if(f(l,t)>f(l,s[k]))
    6. s[k]=t;
    7. return ;
    8. }
    9. int m=(l+r)>>1;
    10. if(f(m,t)>f(m,s[k]))
    11. swap(t,s[k]);
    12. f(l,t)>f(l,s[k])?upd(k<<1,t,l,m):upd(k<<1|1,t,m+1,r);
    13. }

    [NOI2007] 货币兑换 - 洛谷

    1. # include
    2. using namespace std;
    3. typedef long long int ll;
    4. double a[100000+10],b[100000+10],c[100000+10],d[100000+10],k[100000+10],x[100000+10],y[100000+10],r[100000+10];
    5. int n,u;
    6. double f;
    7. int mp[100000*4+10];
    8. # define getval( i, id) (c[i]*x[id]+y[id])
    9. double query(int root,int l,int r)
    10. {
    11. if(l==r)
    12. {
    13. return getval(u,mp[root]);
    14. }
    15. int mid=(l+r)>>1;
    16. return max(getval(u,mp[root]),u>mid?query(root<<1|1,mid+1,r):query(root<<1,l,mid));
    17. }
    18. void update(int root,int t,int l,int r)
    19. {
    20. if(l==r)
    21. {
    22. if(getval(l,t)>getval(l,mp[root]))
    23. mp[root]=t;
    24. return ;
    25. }
    26. int mid=(l+r)>>1;
    27. if(getval(mid,t)>getval(mid,mp[root]))
    28. swap(mp[root],t);
    29. getval(l,t)>getval(l,mp[root])?update(root<<1,t,l,mid):update(root<<1|1,t,mid+1,r);
    30. }
    31. int main()
    32. {
    33. cin>>n>>f;
    34. for(int i=1;i<=n;i++)
    35. {
    36. scanf("%lf%lf%lf",&a[i],&b[i],&r[i]);
    37. c[i]=a[i]/b[i];
    38. d[i]=c[i];
    39. }
    40. sort(c+1,c+1+n);
    41. for(int i=1;i<=n;i++)
    42. {
    43. u=lower_bound(c+1,c+1+n,d[i])-c;
    44. f=max(f,b[i]*query(1,1,n));
    45. x[i]=f/(a[i]+b[i]/r[i]);
    46. y[i]=x[i]/r[i];
    47. update(1,i,1,n);
    48. }
    49. cout<setprecision(3)<
    50. return 0;
    51. }

  • 相关阅读:
    浅谈本地缓存的几种方案选型
    NX二次开发-UFUN创建角度尺寸标注UF_DRF_create_angular_dim
    解决 urllib2 中 CookiesMiddleware 的 cookie 问题
    Jmeter系列-测试计划详细介绍(3)
    《HelloGitHub》第 88 期
    前后端分离项目(十):实现"改"功能(前后端)
    Springboot疫苗接种管理系统-JAVA.JSP【数据库设计、源码、开题报告】
    Ubuntu终端Terminator的安装
    加速CI构建,实现高效流水线——CloudBees CI发布工作区缓存功能
    JVM垃圾回收——垃圾收集器(一)
  • 原文地址:https://blog.csdn.net/jisuanji2606414/article/details/127837285