题面:
题意:
给定一个圆,圆上有n个点,每个点有个属性 hi,第 i 个点与第 i + 1个点距离为 di
定义两个点之间的距离为 2*(hx + hy) + dis (x,y)。
从 x 到 y 可以顺时针走也可以逆时针走,中途会途径其他点(位于所走一侧的x与y之间的点会被途径)
现在给定某一个区间 [ l,r ] ,这个区间内的点均不能走,问在能选的区间内,我选择两个点,这两个点之间的最大距离是多少。
保证能选的点至少有两个。
题解:
由于所给定区间 [ l,r ] 中的点都不能走,如果 l,r区间一旦选定, 那么在能走的区间里面所选的两点 x,y,从x走到y的方式就已经确定了,要么顺时针,要么逆时针。
我们将环复制一倍变成链。
1 2 3 -----n 1 2 3 ----n
那么 x – y 之间的距离为 d [ x ] + d [ x+1 ] +…+ d [ y-1 ] + 2 * ( h [ x ] + h [ y ])
我们写作:
d [ 1 ] + d [ 2 ] +…+ d [ y-1 ] + 2 * h [ y ] + (2 * h [ x ] - (d [ 1 ] + d [ 2 ] +…+ d [ x - 1]))
我们令
d [ 1 ] + d [ 2 ] +…+ d [ k-1 ] + 2 * h [ k ] = Lk
2 * h [ k ] - (d [ 1 ] + d [ 2 ] +…+ d [ k - 1]) = Rk
我们设可选区间为 [ a ,b ],那么我们在 区间[ a ,b ] 中选出最大的 Lx 与 最大的 Ry,相加即是答案。
特别的,考虑 x==y时,由于要选两个不同的点,所以要得到次大值Lxx,与次大值Ryy,取max(Lx+Ryy,Lxx+Ry)。
所以我们用RMQ 预处理出区间最大值和区间次大值。
考虑不能选的区间 [ l , r ]
若 l <= r 那么可选区间为 r + 1 -------- l + n - 1
若 l >r 那么可选区间为 r + 1 ------- l - 1
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<set>
#define ll long long
#define llu unsigned ll
#define ld long double
#define ui unsigned int
#define pr make_pair
#define pb push_back
#define ui unsigned int
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x) (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
#define forhead(x) for(int i=head[(x)];i;i=nt[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
const int maxm=100100;
const int up=100000;
const int hashp=13331;
const int maxn=200100;
int n,m,a,b,lo[maxn];
ll d[maxn],h[maxn];
pair<ll,ll> l[maxn][20][2],r[maxn][20][2];
void get(pair<ll,ll> a[],pair<ll,ll> b[],pair<ll,ll> c[])
{
//在ask的时候会有重复的区间
if(b[0]==c[0]&&b[1]==c[1])
{
a[0]=b[0];
a[1]=b[1];
return ;
}
else if(b[0]==c[0])
{
a[0]=b[0];
a[1]=max(b[1],c[1]);
return ;
}
if(b[0]<=c[0])
{
a[0]=c[0];
a[1]=max(b[0],c[1]);
}
else
{
a[0]=b[0];
a[1]=max(b[1],c[0]);
}
}
void rmq(void)
{
lo[0]=-1;
for(int i=1;i<=n*2;i++)
{
l[i][0][0]=pr(d[i-1]+2*h[i],i);
l[i][0][1]=pr(-lnf,-1);
r[i][0][0]=pr(-d[i-1]+2*h[i],i);
r[i][0][1]=pr(-lnf,-1);
lo[i]=(i&(i-1))==0?lo[i-1]+1:lo[i-1];
d[i]+=d[i-1];
}
int t=lo[n*2]+1;
for(int j=1;j<=t;j++)
{
for(int i=1;i<=2*n-(1<<j)+1;i++)
{
get(l[i][j],l[i][j-1],l[i+(1<<(j-1))][j-1]);
get(r[i][j],r[i][j-1],r[i+(1<<(j-1))][j-1]);
}
}
}
ll ask(int cl,int cr)
{
pair<ll,ll>nowl[2],nowr[2];
int k=lo[cr-cl+1];
get(nowl,l[cl][k],l[cr-(1<<k)+1][k]);
get(nowr,r[cl][k],r[cr-(1<<k)+1][k]);
if(nowl[0].second!=nowr[0].second) return nowl[0].first+nowr[0].first;
else return max(nowl[0].first+nowr[1].first,nowl[1].first+nowr[0].first);
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&d[i]),d[i+n]=d[i];
for(int i=1;i<=n;i++)
scanf("%lld",&h[i]),h[i+n]=h[i];
rmq();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(a<=b) printf("%lld\n",ask(b+1,a+n-1));
else printf("%lld\n",ask(b+1,a-1));
}
return 0;
}