【bzoj2388】【旅行规划】【分块+凸包】

来源:互联网 发布:网络直播平台赚钱吗 编辑:程序博客网 时间:2024/04/27 11:45

Description

OIVillage是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl决定修建了一条铁路将当地n个最著名的经典连接起来,让游客可以通过火车从铁路起点(1号景点)出发,依次游览每个景区。为了更好的评价这条铁路,xkszltl为每一个景区都哦赋予了一个美观度,而一条旅行路径的价值就是它所经过的景区的美观度之和。不过,随着天气与季节的变化,某些景点的美观度也会发生变化。
xkszltl希望为每位旅客提供最佳的旅行指导,但是由于游客的时间有限,不一定能游览全部景区,然而他们也不希望旅途过于短暂,所以每个游客都希望能在某一个区间内的车站结束旅程,而xkszltl的任务就是为他们选择一个终点使得旅行线路的价值最大。可是当地的景点与前来观光的旅客实在是太多了,xkszltl无法及时完成任务,于是找到了准备虐杀NOI2011的你,希望你能帮助他完成这个艰巨的任务。

Input

第一行给出一个整数n,接下来一行给出n的景区的初始美观度。
第三行给出一个整数m,接下来m行每行为一条指令:
1.         0 x y k:表示将x到y这段铁路边上的景区的美观度加上k;
2.         1 x y:表示有一名旅客想要在x到y这段(含x与y)中的某一站下车,你需要告诉他最大的旅行价值。

Output

对于每个询问,输出一个整数表示最大的旅行价值。

Sample Input

5
1 8 -8 3 -7
3
1 1 5
0 1 3 6
1 2 4

Sample Output

9
22

HINT



Data Limit:

对于20%的数据,n,m≤3000;

对于40%的数据,n,m≤30000;

对于50%的数据,n,m≤50000;

另外20%的数据,n,m≤100000,修改操作≤20;

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

题解:

          设s[i]为i位置美观度的前缀和.

          把(i,s[i])看成一个点,考虑分块.

          对于每一块,维护一个上凸壳,对于整块的询问就可以在凸壳上二分.

          修改的时候可以发现是加一个等差数列,所以对于整块的可以直接打标记.

          边缘的部分暴力修改然后暴力重构凸壳.

          对于每次修改的右端点之后的块,等于是整块加一个值,

          这样最优值的位置是不变的,所以直接打标记即可.

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#define N 100010#define M 400#define ll long long#define inf 1LL<<60 using namespace std;int bk,n,m,cnt,kind,x,y,bl[N],l[M],r[M],st[N],xu[M][M],size[M];ll s[N],f[M],d[M],c[M],k,temp;int read(){  int x(0),f(1);char ch=getchar();  while (ch<'0'||ch>'9') { if (ch=='-')f=-1;ch=getchar();}  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();  return x*f;}void getbk(){  bk=sqrt(n);  if (n%bk) cnt=n/bk+1;  else cnt=n/bk;  for (int i=1;i<=n;i++)    bl[i]=(i-1)/bk+1;  for (int i=1;i<=cnt;i++){    l[i]=(i-1)*bk+1;    r[i]=min(n,bk*i);  }}double cal(int x,int y){  return (double)(s[y]-s[x])/(double)(y-x); } void build(int x){  int top=0;  st[++top]=l[x];  for (int i=l[x]+1;i<=r[x];i++){    while (top>1&&cal(st[top-1],st[top])<cal(st[top-1],i)) top--;    st[++top]=i;  }  st[0]=0;st[top+1]=n+1;size[x]=top;  for (int i=0;i<=top+1;i++) xu[x][i]=st[i];}void pushdown(int x){  temp=f[x];  for (int i=l[x];i<=r[x];i++){     s[i]+=temp;temp+=d[x];s[i]+=c[x];  }  f[x]=c[x]=d[x]=0; }void change(int x,int y,ll k){  int a=bl[x],b=bl[y];  temp=k*(l[a+1]-x+1);  for (int i=a+1;i<b;i++){     f[i]+=temp;d[i]+=k;     temp+=k*(r[i]-l[i]+1);   }  pushdown(a);temp=k;  for (int i=x;i<=min(y,r[a]);i++){    s[i]+=temp;temp+=k;  }  build(a);pushdown(b);  if (a!=b){    temp=k*(l[b]-x+1);    for (int i=l[b];i<=y;i++){      s[i]+=temp;temp+=k;    }   }  temp=k*(y-x+1);  for (int i=y+1;i<=r[b];i++)    s[i]+=temp;  build(b);  for (int i=b+1;i<=cnt;i++)    c[i]+=temp;}ll getval(int x){  ll ans(0);  if (x==0||x==n+1) return -inf;  int t=bl[x];  ans=s[x]+c[t];  ans+=(x-l[t])*d[t]+f[t];  return ans;}ll ask(int x){  int a=1,b=size[x];  while (a<=b){    int mid=(a+b)>>1;    ll t1=getval(xu[x][mid-1]);    ll t2=getval(xu[x][mid]);    ll t3=getval(xu[x][mid+1]);    if (t1<t2&&t2<t3) a=mid+1;    else if (t3<t2&&t2<t1) b=mid-1;    else return t2;       }}ll query(int x,int y){  int a=bl[x],b=bl[y];  ll ans=-inf;   for (int i=a+1;i<b;i++)    ans=max(ans,ask(i));  for (int i=x;i<=min(y,r[a]);i++)    ans=max(ans,getval(i));  if (a!=b){    for (int i=l[b];i<=y;i++)      ans=max(ans,getval(i));  }  return ans;}int main(){  n=read();  for (int i=1;i<=n;i++){    x=read();    s[i]=s[i-1]+x;  }   getbk();  for (int i=1;i<=cnt;i++) build(i);  m=read();  for (int i=1;i<=m;i++){    kind=read();x=read();y=read();    if (kind==0){k=read();change(x,y,k);}    else printf("%lld\n",query(x,y));  }}


0 0
原创粉丝点击