旅行规划(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\n",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

猜你喜欢

转载自www.cnblogs.com/liankewei/p/10587639.html