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]);
}
}
}