https://www.51nod.com/Challenge/Problem.html#!#problemId=1593
题意:
环形公园里有n棵树,一些孩子会占据几棵连续的树,m组询问,每组询问中一只猴子要选两棵树,从一棵到另一棵,中间不经过孩子,消耗的能量为两树间距离+2*两棵树的高,求消耗能量最大值。
思路:
https://blog.csdn.net/ZLH_HHHH/article/details/74887389
这篇讲的非常清楚。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 600000+100;
typedef long long ll;
int n,m,d[maxn],h[maxn],minn[20][maxn],maxx[20][maxn];
ll ds[maxn],A[maxn],B[maxn];
void RMQ_init()
{
for(int i=1;i<=2*n;i++)maxx[0][i]=i,minn[0][i]=i;
for(int k=1;(1<<k)<=2*n;k++)
{
for(int i=1;i+(1<<k)-1<=2*n;i++)
{
maxx[k][i]= (A[maxx[k-1][i]] > A[maxx[k-1][i+(1<<(k-1))]] ?maxx[k-1][i]:maxx[k-1][i+(1<<(k-1))]);
minn[k][i]= (B[minn[k-1][i]] < B[minn[k-1][i+(1<<(k-1))]] ?minn[k-1][i]:minn[k-1][i+(1<<(k-1))]);
}
}
}
int RMQ(int l,int r,int flag)
{
int k=0;
while((1<<(k+1))<=(r-l+1))k++;
if(flag==0)return A[maxx[k][l]] > A[maxx[k][r-(1<<k)+1]] ?maxx[k][l]:maxx[k][r-(1<<k)+1];
else return B[minn[k][l]] < B[minn[k][r-(1<<k)+1]] ?minn[k][l]:minn[k][r-(1<<k)+1];
}
void solve(int a,int b)
{
int x=RMQ(a,b,0),y=RMQ(a,b,1);
if(x!=y)printf("%lld\n",A[x]-B[y]);
else
{
ll ans=-(1<<30);
if(y!=a)ans=max(ans,A[x]-B[RMQ(a,y-1,1)]);
if(y!=b)ans=max(ans,A[x]-B[RMQ(y+1,b,1)]);
if(x!=a)ans=max(ans,A[RMQ(a,x-1,0)]-B[y]);
if(x!=b)ans=max(ans,A[RMQ(x+1,b,0)]-B[y]);
printf("%lld\n",ans);
}
}
int main()
{
//freopen("input.in","r",stdin);
int a,b;
cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%d",&d[i]);
for(int i=1;i<=n;i++)scanf("%d",&h[i]);
for(int i=n+1;i<=2*n;i++)d[i]=d[i-n],h[i]=h[i-n];
for(int i=1;i<=2*n;i++)ds[i]=ds[i-1]+d[i-1];
for(int i=1;i<=2*n;i++)A[i]=ds[i]+2*h[i];
for(int i=1;i<=2*n;i++)B[i]=ds[i]-2*h[i];
RMQ_init();
while(m--)
{
scanf("%d%d",&a,&b);
a--,b++;
swap(a,b);
if(a>b)b+=n;
solve(a,b);
}
return 0;
}