题目描述
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,m≤100000
solution
要支持区间加一个一次函数,求最大值,线段树支持不了。
我们考虑用分块凸包。
一段区间加一次函数,凸包是不会变的。
这一点我当时没有想到,于是就想不出来。
加这一段一次函数的时候,每一条边的斜率都加了相同的数,也就是斜率大小关系不变。
那么凸包就不变了。
查询的话凸包上二分斜率找到分界点。单块的暴力查。
效率O(n^1.5*logn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }