• 旅行规划(travel)


    题目描述

    OIVillage 是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl 决定修建了一条铁路将当地 nnn 个最著名的经典连接起来,让游客可以通过火车从铁路起点( 111 号景点)出发,依次游览每个景区。为了更好的评价这条铁路,xkszltl 为每一个景区都赋予了一个美观度,而一条旅行路径的价值就是它所经过的景区的美观度之和。不过,随着天气与季节的变化,某些景点的美观度也会发生变化。

    xkszltl 希望为每位旅客提供最佳的旅行指导,但是由于游客的时间有限,不一定能游览全部景区,然而他们也不希望旅途过于短暂,所以每个游客都希望能在某一个区间内的车站结束旅程,而 xkszltl 的任务就是为他们选择一个终点使得旅行线路的价值最大。可是当地的景点与前来观光的旅客实在是太多了,xkszltl 无法及时完成任务,于是找到了准备虐杀 NOI2019 的你,希望你能帮助他完成这个艰巨的任务。

    输入格式

    第一行给出一个整数 nnn,接下来一行给出 nnn 的景区的初始美观度。

    第三行给出一个整数 mmm,接下来 mmm 行每行为一条指令:

    1.   0 x y k1.~~~0~x~y~k1.   0 x y k:表示将 xxx 到 yyy 这段铁路边上的景区的美观度加上 kkk;

    2.   1 x y2.~~~1~x~y2.   1 x y:表示有一名旅客想要在 xxx 到 yyy 这段(含 xxx 与 yyy )中的某一站下车,你需要告诉他最大的旅行价值。

    对于 100%100\%100% 的数据,n,m≤100000n,m≤100000n,m100000


    solution

    要支持区间加一个一次函数,求最大值,线段树支持不了。

    我们考虑用分块凸包。

    一段区间加一次函数,凸包是不会变的。

    这一点我当时没有想到,于是就想不出来。

    加这一段一次函数的时候,每一条边的斜率都加了相同的数,也就是斜率大小关系不变。

    那么凸包就不变了。

    查询的话凸包上二分斜率找到分界点。单块的暴力查。

    效率O(n^1.5*logn)

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<cmath>
      7 #define maxn 100005
      8 #define ll long long
      9 #define inf 1e15
     10 using namespace std;
     11 int n,m,M,o;
     12 ll ans,a[maxn];
     13 struct no{ll x,y;};
     14 struct node{
     15     int ne,l,r,len,top;
     16     ll p[405],bj,bk;
     17     no t[405];
     18 }s[405];
     19 void add_p(int id,int i,ll v){
     20     s[id].ne=1;
     21     int pl=i-s[id].l+1;
     22     s[id].p[pl]+=v;
     23     
     24 }
     25 void add(int id,ll v,ll k){
     26     s[id].bj+=v;s[id].bk+=k;
     27 }
     28 ll cr(no a,no b){
     29     return a.x*b.y-a.y*b.x;
     30 }
     31 void build(int id){
     32     s[id].ne=0;
     33     for(int i=1;i<=s[id].len;i++){
     34         s[id].p[i]+=s[id].bj;
     35         s[id].p[i]+=s[id].bk*i;
     36     }
     37     s[id].bj=s[id].bk=0;int tp=0;
     38     for(int i=1;i<=s[id].len;i++){
     39         while(tp>1&&cr(
     40             (no){i-s[id].t[tp-1].x,s[id].p[i]-s[id].t[tp-1].y}
     41             ,(no){s[id].t[tp].x-s[id].t[tp-1].x,s[id].t[tp].y-s[id].t[tp-1].y}
     42         )<0)tp--;
     43         s[id].t[++tp]=(no){i,s[id].p[i]};
     44     }
     45     s[id].top=tp;
     46 }
     47 double getk(no a,no b){
     48     return (a.y-b.y)/(a.x-b.x);
     49 }
     50 void ask(int id){
     51     if(s[id].ne)build(id);
     52     int l=1,r=s[id].top;
     53     while(l+1<r){
     54         int mid=(l+r)>>1;
     55         if(mid==1||mid==s[id].top)break;
     56         double lk=getk(s[id].t[mid],s[id].t[mid-1])+s[id].bk;
     57         double rk=getk(s[id].t[mid+1],s[id].t[mid])+s[id].bk;
     58         if(rk>0)l=mid;
     59         else if(lk<0)r=mid;
     60         else {l=r=mid;break;}
     61     }
     62     ll Max=-inf;
     63     for(int i=l-3;i<=r+3;i++){
     64         if(i<1||i>s[id].top)continue;
     65         int c=s[id].t[i].x;
     66         Max=max(Max,s[id].p[c]+s[id].bj+s[id].bk*c);
     67     }
     68     ans=max(ans,Max);
     69 }
     70 void ask_p(int id,int i){
     71     
     72     if(s[id].ne)
     73     build(id);
     74     int pl=i-s[id].l+1;
     75     if(i<s[id].l||i>s[id].r)while(1);
     76     ans=max(ans,s[id].p[pl]+s[id].bj+s[id].bk*pl);
     77 }
     78 int main()
     79 {
     80     cin>>n;o=sqrt(n);
     81     for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]+=a[i-1];
     82     int la=0;
     83     for(int i=0;;i++){
     84         s[i].l=max(la,1),s[i].r=min(la+o-1,n);
     85         s[i].len=s[i].r-s[i].l+1;M=i;
     86         if(s[i].r==n)break;
     87         la=la+o;
     88     }s[M+1].l=1e9;
     89     for(int i=1;i<=n;i++)add_p(i/o,i,a[i]);
     90     cin>>m;
     91     for(int ix=1,op,x,y;ix<=m;ix++){
     92         scanf("%d",&op);
     93         if(op==1){
     94             scanf("%d%d",&x,&y);
     95             int li=x/o,ri=y/o;ans=-inf;
     96             for(int i=li+1;i<ri;i++)ask(i);
     97             for(;x<s[li+1].l&&x<=y;x++)ask_p(x/o,x);
     98             for(;y>s[ri-1].r&&y>=x;y--)ask_p(y/o,y);
     99             printf("%lld
    ",ans);
    100         }
    101         else {ll v;
    102             scanf("%d%d%lld",&x,&y,&v);int st=x,ed=y;
    103             int li=x/o,ri=y/o;
    104             for(int i=li+1;i<ri;i++)add(i,(s[i].l-st)*v,v);
    105             for(;x<s[li+1].l&&x<=y;x++)add_p(x/o,x,(x-st+1)*v);
    106             for(;y>s[ri-1].r&&y>=x;y--)add_p(y/o,y,(y-st+1)*v);
    107             for(int i=ri+1;i<=M;i++)add(i,(ed-st+1)*v,0);
    108             for(int i=ed+1;i<s[ri+1].l&&i<=n;i++)add_p(i/o,i,(ed-st+1)*v);
    109         }
    110     }
    111     return 0;
    112 }
    View Code
  • 相关阅读:
    springboot ssm propertis 如何搭建多数据源动态切换
    发送验证码
    二维码生成
    文件上传 下载
    git拉代码报错
    通过url 下载文件
    原生JS实现挡板小球游戏
    深入浅出解析AJAX
    深入解析CSS3圆周运动
    JS递归原理
  • 原文地址:https://www.cnblogs.com/liankewei/p/10587639.html
Copyright © 2020-2023  润新知