题目描述
OIVillage 是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl 决定修建了一条铁路将当地
xkszltl 希望为每位旅客提供最佳的旅行指导,但是由于游客的时间有限,不一定能游览全部景区,然而他们也不希望旅途过于短暂,所以每个游客都希望能在某一个区间内的车站结束旅程,而 xkszltl 的任务就是为他们选择一个终点使得旅行线路的价值最大。可是当地的景点与前来观光的旅客实在是太多了,xkszltl 无法及时完成任务,于是找到了准备虐杀 NOI2019 的你,希望你能帮助他完成这个艰巨的任务。
输入格式
第一行给出一个整数
第三行给出一个整数
对于
要支持区间加一个一次函数,求最大值,线段树支持不了。
我们考虑用分块凸包。
一段区间加一次函数,凸包是不会变的。
这一点我当时没有想到,于是就想不出来。
加这一段一次函数的时候,每一条边的斜率都加了相同的数,也就是斜率大小关系不变。
那么凸包就不变了。
查询的话凸包上二分斜率找到分界点。单块的暴力查。
效率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