CF515E Drazil and Park
题面翻译
有一只猴子,他生活在一个环形的公园里。有 \(n\) 棵树围绕着公园。第 \(i\) 棵树和第 \(i+1\) 棵树之间的距离是 \(d_i\),而第n棵树和第一棵树之间的距离是 \(d_n\),第i棵树的高度是 \(h_i\),
这只猴子每天要进行晨跑。晨跑的步骤如下:
· 他先选择两棵树;
· 然后爬上第一棵树;
· 再从第一棵树上下来,接着围绕着公园跑(有两个可能的方向)到第二棵树,然后爬上第二棵树;
· 最后从第二棵树上下来。
但是有一些小孩会在连续的一些树上玩耍。所以猴子不能经过这些树。
比如现在猴子选择的第\(x\)棵和第\(y\)棵树,那么该早晨他消耗的能量是 \(2(hx+hy)+dist(x,y)\) 。由于某一条路径是被小孩子占据的,所以他只能跑另外一条,因此 \(dist(x,y)\) 是确定的。
现在给出第i天,孩子们会在第 \(a_i\) 棵树和 bi 棵树之间玩耍。具体的,如果 \(ai≤bi\) ,那么孩子玩耍的区间就是 \([ai,bi]\) ,否则孩子玩耍的区间就是 \([ai,n]⋃ [1,bi]\) 。
请帮助这只猴子找出两棵树,让他晨跑的时候他能够消耗最大的能量。
样例 #1
样例输入 #1
5 3
2 2 2 2 2
3 5 2 1 4
1 3
2 2
4 5
样例输出 #1
12
16
18
样例 #2
样例输入 #2
3 3
5 1 4
5 1 4
3 3
2 2
1 1
样例输出 #2
17
22
11
分析
首先化环为链,设 \(s[]\) 为 \(d[]\) 的前缀和,则 \(dis(x,y)=s[y]-s[x]\)
题目要求 \(2(h_x+h_y)+dis(x,y)\) 最大,则 \(2h_x+2h_y+s[y]-s[x]\) 最大
则有 \(2h_y+s[y]+(2h_x-s[x])\) 最大,也就是让 \(2h_y+s[y]\) 最大,\(2h_x-s[x]\) 最小,线段树维护两个答案即可。
但是需要考虑如果查询出来的两个位置 \(pos\) 相等,需要在 \([l,pos-1],[pos+1,r]\) 区间内再查一次最大最小值即可。
同时注意到刚才我们要查的是位置,所以维护 RMQ 信息的时候要维护的是 RMQ 的下标。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,sum;
int d[700005],h[700005],maxx[300005<<2],minn[300005<<2],sum1[700005],sum2[700005];
int getmax(int x,int y){return sum1[x]>sum1[y]?x:y;}
int getmin(int x,int y){return sum2[x]<sum2[y]?x:y;}
void pushup(int num){
maxx[num]=getmax(maxx[num<<1],maxx[num<<1|1]);
minn[num]=getmin(minn[num<<1],minn[num<<1|1]);
}
void build(int l,int r,int num){
if(l==r){
maxx[num]=minn[num]=l;
return;
}
int mid=l+r>>1;
build(l,mid,num<<1),build(mid+1,r,num<<1|1);
pushup(num);
}
int querymax(int l,int r,int num,int x,int y){
if(x>r||y<l)return 700003;
if(x<=l&&r<=y)return maxx[num];
int mid=l+r>>1;
return getmax(querymax(l,mid,num<<1,x,y),querymax(mid+1,r,num<<1|1,x,y));
}
int querymin(int l,int r,int num,int x,int y){
if(x>r||y<l)return 700003;
if(x<=l&&r<=y)return minn[num];
int mid=l+r>>1;
return getmin(querymin(l,mid,num<<1,x,y),querymin(mid+1,r,num<<1|1,x,y));
}
int calcmax(int l,int r){return l>r?0:querymax(1,n<<1|1,1,l,r);}
int calcmin(int l,int r){return l>r?0:querymin(1,n<<1|1,1,l,r);}
int solve(int l,int r){
int maxxx=calcmax(l,r),minnn=calcmin(l,r);
if(maxxx==minnn){
int maxxxx=getmax(calcmax(l,maxxx-1),calcmax(maxxx+1,r));
int minnnn=getmin(calcmin(l,minnn-1),calcmin(minnn+1,r));
return max(sum1[maxxxx]-sum2[minnn],sum1[maxxx]-sum2[minnnn]);
}
return sum1[maxxx]-sum2[minnn];
}
signed main(){
cin>>n>>m;sum1[700003]=-LONG_LONG_MAX,sum2[700003]=LONG_LONG_MAX;
for(int i=1;i<=n;i++)cin>>d[i%n+1],d[i%n+1+n]=d[i%n+1];
for(int i=1;i<=n;i++)cin>>h[i],h[i+n]=h[i];
sum1[0]=-LONG_LONG_MAX,sum2[0]=LONG_LONG_MAX;
for(int i=1;i<=(n<<1|1);i++){
sum+=d[i];
sum1[i]=sum+(h[i]<<1),sum2[i]=sum-(h[i]<<1);
}
build(1,n<<1|1,1);
for(int i=1,l,r;i<=m;i++){
cin>>l>>r;
if(l<=r)cout<<solve(r+1,l-1+n)<<endl;
else cout<<solve(r+1,l-1)<<endl;
}
return 0;
}

浙公网安备 33010602011771号