bzoj 2388: 旅行规划 (分块+凸包+三分)
2017-01-17 23:19
239 查看
2388: 旅行规划
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 281 Solved: 78
[Submit][Status][Discuss]
Description
[align=center]OIVillage是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl决定修建了一条铁路将当地n个最著名的经典连接起来,让游客可以通过火车从铁路起点(1号景点)出发,依次游览每个景区。为了更好的评价这条铁路,xkszltl为每一个景区都哦赋予了一个美观度,而一条旅行路径的价值就是它所经过的景区的美观度之和。不过,随着天气与季节的变化,某些景点的美观度也会发生变化。[/align]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
51 8 -8 3 -7
3
1 1 5
0 1 3 6
1 2 4
Sample Output
922
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<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 100003 #define LL long long using namespace std; const LL inf=1e18; int belong ,block,l ,r ,n,m; LL delta ,k ,s ; struct point{ LL x,y; point (LL X=0,LL Y=0){ x=X,y=Y; } }a ,ch ; 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<b.x||a.x==b.x&&a.y<b.y; } LL cross(point a,point b) { return a.x*b.y-a.y*b.x; } void build(int num) { sort(a+l[num],a+r[num]+1,cmp); if (r[num]-l[num]+1<=2) { c[num].size=r[num]-l[num]+1; for (int i=1;i<=c[num].size;i++) c[num].x[i]=a[i+l[num]-1]; return; } int m=0; int pos=m; for (int i=r[num];i>=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]); } } }
相关文章推荐
- bzoj2388 旅行规划(分块+凸包+三分)
- BZOJ 2388: 旅行规划 [分块 凸包 等差数列]
- bzoj2388: 旅行规划【分块+凸包】
- bzoj 2388 旅行规划 分块+二分+凸包
- 【bzoj2388】【旅行规划】【分块+凸包】
- BZOJ2388: 旅行规划
- bzoj2388 旅行规划
- BZOJ2388 : 旅行规划
- BZOJ2388: 旅行规划
- BZOJ2388: 旅行规划
- 【Codeforces Round 335 (Div 2)E】【计算几何-凸包 线性规划 三分凸包上最优点】Freelancer's Dreams 二维属性 充最少的钱变得满足要求 [计算几何-凸包模
- BZOJ 4501: 旅行 01分数规划 最大权闭合子图
- BZOJ 3203 Sdoi2013 保护出题人 凸包+三分
- BZOJ 3203 凸包+三分
- bzoj 1690: [Usaco2007 Dec]奶牛的旅行【01分数规划+spfa】
- 【bzoj1690】【Usaco2007 Dec】【奶牛的旅行】【分数规划】
- bzoj 2961 共点圆 cdq+凸包+三分
- 【bzoj5089】最大连续子段和 分块+单调栈维护凸包
- 【BZOJ1690】【Usaco2007 Dec】奶牛的旅行 分数规划 判断负环
- bzoj2402: 陶陶的难题II【分数规划+树链剖分+线段树维护凸包】