bzoj 2388: 旅行规划 (分块+凸包+三分)

2388: 旅行规划

Time Limit: 50 Sec   Memory Limit: 128 MB
Submit: 281   Solved: 78
[ Submit][ Status][ Discuss]

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。

Source

[ Submit][ Status][ Discuss]


题解:分块+凸包+三分

因为是前缀和,所以我们不好直接用数据结构维护。所以我们将序列分块,然后对于块内维护delta,k,s[x],delta表示是该块中所有的位置共同的累加量,k表示的是每个位置都要增加(x-l+1)*K(l表示该块第一个元素的位置),s[x]表示的是x位置的前缀和。

对于一个块内的最大值,我们相当于查询delta+max(s[x]+k*(x-l+1))。设yi=s[i],xi=i,那么我们要求的其实就是z=yi+k*(xi-l+1),看做是一条过(xi,yi)斜率为-k的直线与y轴截距的最大值。我们可以发现取最大值的点一定在该区域点的上凸壳上,所以我们对于每个块维护凸壳,然后查找的时候在凸包上三分即可。

对于修改,我们暴力修改不完整的块,然后重建凸壳,对于完整的块,我们直接修改delta,k.

对于查询,我们暴力不完整块的最大值,对于完整的块,我们在凸壳上三分。

#include  
#include  
#include  
#include  
#include  
#define N 100003  
#define LL long long 
using namespace std; 
const LL inf=1e18;
int belong[N],block,l[N],r[N],n,m;  
LL delta[N],k[N],s[N];
struct point{  
    LL x,y;  
    point (LL X=0,LL Y=0){  
        x=X,y=Y;  
    }  
}a[N],ch[N];  
point operator -(point a,point b)  
{  
    return point (a.x-b.x,a.y-b.y);  
}  
struct data{  
    int size;  
    point x[400];  
}c[400];  
int cmp(point a,point b)  
{  
    return a.x=l[num];i--){  
        while (m>1&&cross(ch[m-1]-ch[m-2],a[i]-ch[m-2])<=0) m--;  
        ch[m++]=a[i];  
    }  
    m--;  
    c[num].size=m-pos+1;   
    int t=0;  
    for (int i=m;i>=0;i--)  
     c[num].x[++t]=ch[i];  
}  
bool check(int x1,int x2,int num)  
{  
    LL t1=(LL)(c[num].x[x1].x-l[num]+1)*k[num]+c[num].x[x1].y;  
    LL t2=(LL)(c[num].x[x2].x-l[num]+1)*k[num]+c[num].x[x2].y;  
    return t1>t2;  
}  
LL solve(int num)  
{  
    int ls=1; int rs=c[num].size;  
    int ans=0;  
    while (ls<=rs) {  
        int mid=(ls+rs)/2;  
        int mid1=(mid+rs+1)/2;  
        if (check(mid1,mid,num)) ls=mid+1;  
        else rs=mid1-1;  
    }  
    return (LL)(c[num].x[ls].x-l[num]+1)*k[num]+c[num].x[ls].y;  
}  
int main()  
{  
    freopen("a.in","r",stdin);  
    freopen("my.out","w",stdout);  
    scanf("%d",&n);  
    for (int i=1;i<=n;i++) {  
        LL x; scanf("%I64d",&x);  
        s[i]=s[i-1]+x;  
        a[i].x=i; a[i].y=s[i];   
    }  
    block=sqrt(n);  
    int t=ceil(n*1.0/block);   
    for (int i=1;i<=t;i++) l[i]=n,r[i]=0;  
    for (int i=1;i<=n;i++){  
      belong[i]=(i-1)/block+1;  
      l[belong[i]]=min(l[belong[i]],i);  
      r[belong[i]]=max(r[belong[i]],i);  
    }  
    for (int i=1;i<=t;i++) build(i);  
    scanf("%d",&m);  
    for (int i=1;i<=m;i++){  
        int opt,x,y; LL val;  
        scanf("%d%d%d",&opt,&x,&y);  
        if (opt==1) {  
            LL mx=-inf;  
            if (belong[x]==belong[y]) {  
                for (int j=x;j<=y;j++) mx=max(mx,s[j]+delta[belong[x]]+k[belong[x]]*(LL)(j-l[belong[x]]+1));  
                printf("%I64d\n",mx);  
                continue;  
            }  
            for (int j=x;j<=r[belong[x]];j++) mx=max(mx,s[j]+delta[belong[x]]+k[belong[x]]*(LL)(j-l[belong[x]]+1));  
            for (int j=l[belong[y]];j<=y;j++)   
             mx=max(mx,s[j]+delta[belong[y]]+k[belong[y]]*(LL)(j-l[belong[y]]+1));  
            for (int j=belong[x]+1;j<=belong[y]-1;j++)  
             mx=max(mx,solve(j)+delta[j]);  
            printf("%I64d\n",mx);  
        }  
        if (opt==0) {  
            scanf("%I64d",&val);  
            if (belong[x]==belong[y]) {  
                for (int j=x;j<=y;j++)  
                 s[j]+=(LL)(j-x+1)*val,a[j].y=s[j];  
                for (int j=y+1;j<=r[belong[y]];j++) s[j]+=(LL)(y-x+1)*val,a[j].y=s[j];  
                for (int j=belong[y]+1;j<=t;j++) delta[j]+=(LL)(y-x+1)*val;  
                build(belong[x]);  
                continue;  
            }  
            for (int j=belong[x]+1;j<=belong[y]-1;j++)  
             delta[j]+=(LL)(l[j]-x)*val,k[j]+=val;  
            for (int j=x;j<=r[belong[x]];j++) s[j]+=(LL)(j-x+1)*val,a[j].y=s[j];  
            build(belong[x]);  
            for (int j=l[belong[y]];j<=y;j++) s[j]+=(LL)(j-x+1)*val,a[j].y=s[j];  
            for (int j=y+1;j<=r[belong[y]];j++) s[j]+=(LL)(y-x+1)*val,a[j].y=s[j];  
            for (int j=belong[y]+1;j<=t;j++) delta[j]+=(LL)(y-x+1)*val;  
            build(belong[y]);  
        }  
    }  
}  



你可能感兴趣的:(分块,计算几何,三分)