51nod 1593 公园晨跑
原题链接
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1593
题目中,猴子消耗的能量等于:
两个点的距离加上两个点上 树的高度的2倍
我们可以把环撕开,变为链,因为路径是环上连续的一段。
任何一段都可以映射到序列:
1,2,3,4,...n,1,2,3,4,...n
把询问环,变为某一个区间
令 ,第i棵树的高度为
hi
令,第1个点在0位置,第i个点相对于第1个点的位置为:
di
如果,选定 x,y作为猴子选择的两个棵树的编号,那么它消耗的能量为:
∣∣dx−dy∣∣+2hx+2hy
令 x<y
∣∣dx−dy∣∣+2hx+2hy=dy−dx+2hx+2hy=(dy+2hy)−(dx−2hx)
令 :
A[x]=dx+2hxB[x]=dx−2hx
原问题等价于计算,指定区间 [L,R] 内:
maxx,y∈[L,R] , x≠y(A[x]−B[y])
假设 x=X,y=Y 时 有:
maxx∈[L,R]A[x]=A[X]miny∈[L,R]B[y]=B[Y]
当 X≠Y 时:
maxx,y∈[L,R] , x≠y(A[x]−B[y])=A[X]−B[Y]
当 X=Y 时:
假设有 满足下面等式的 a,b
maxx,y∈[L,R] , x≠y(A[x]−B[y])=A[a]−B[b]
如果 a≠X 且 b≠Y ,又因为 , A[X]>A[a] ,B[Y]<B[b]
所以:
A[X]−B[b]>A[a]−B[b]A[a]−B[Y]>A[a]−B[b]
与上文矛盾。
所以有:
a=X 或者 b=Y ,且二者不同时成立
所以,利用线段树求出区间最大值(A中)与最小值(B中)的下标,
如果两个最值在同一个位置,即 X=Y 则枚举:
a=X 时的答案,有:
B[b]=miny∈[L,R],y≠YB[y]
b=Y 时的答案,有:
A[a]=maxx∈[L,R],x≠XB[x]
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define MAXN 300005
using namespace std;
typedef long long LL;
typedef pair<LL,LL>P;
struct point
{
int c[2];
LL ma;
int x;
point()
{
c[0]=c[1]=0;
ma=-0x3f3f3f3f3f3f3f3f;
}
};
struct Bt
{
point A[MAXN*8];
int deep;
int root;
LL ma;
LL key;
int xx;
int n;
Bt()
{
root=1;
deep=2;
}
void update(point &a)
{
if(A[a.c[0]].ma>A[a.c[1]].ma)
{
a.ma=A[a.c[0]].ma;
a.x=A[a.c[0]].x;
}
else
{
a.ma=A[a.c[1]].ma;
a.x=A[a.c[1]].x;
}
}
void _insert(int x,int L,int R,int &k)
{
if(x>R||x<L)return ;
if(!k)k=deep++;
if(L==R)
{
A[k].ma=key;
A[k].x=x;
return ;
}
int mid=(L+R)>>1;
_insert(x,L,mid,A[k].c[0]);
_insert(x,mid+1,R,A[k].c[1]);
update(A[k]);
}
void insert(int x,LL ke)
{
key=ke;
_insert(x,0,n,root);
}
void _query(int l,int r,int L,int R,int k)
{
if(R<l||L>r)return ;
if(L>=l&&R<=r)
{
if(A[k].ma>ma)
{
ma=A[k].ma;
xx=A[k].x;
}
return ;
}
int mid=(L+R)>>1;
_query(l,r,L,mid,A[k].c[0]);
_query(l,r,mid+1,R,A[k].c[1]);
}
int query(int l,int r)
{
ma=-0x3f3f3f3f3f3f3f3f;
_query(l,r,0,n,root);
return xx;
}
}T1,T2;
LL S1[MAXN*2];
LL S2[MAXN*2];
int main ()
{
int n,m,s,l,r;
LL h;
scanf("%d %d",&n,&m);
s=n<<1;
for(int i=1;i<=n;i++)
{
scanf("%lld",S1+i);
}
for(int i=n+1,t=1;i<s;i++,t++) S1[i]=S1[t];
for(int i=1;i<s;i++) S1[i]+=S1[i-1];
for(int i=0;i<s;i++) S2[i]=S1[i];
for(int i=0;i<n;i++)
{
scanf("%lld",&h);
h=h<<1;
S1[i]+=h;
S2[i]-=h;
S1[i+n]+=h;
S2[i+n]-=h;
}
T1.n=s-1;
T2.n=s-1;
for(int i=0;i<s;i++)
{
T1.insert(i,S1[i]);
T2.insert(i,-S2[i]);
}
while(m--)
{
scanf("%d %d",&l,&r);
l--;
r--;
if(l<=r)
{
int u=r+1;
r=n+l-1;
l=u;
}
else
{
swap(l,r);
l++;
r--;
}
int ma=T1.query(l,r);
int mi=T2.query(l,r);
if(ma==mi)
{
int ma1=-1;
if(ma>l)
ma1=T1.query(l,ma-1);
if(ma<r)
{
int u=T1.query(ma+1,r);
if(ma1==-1||S1[ma1]<S1[u])ma1=u;
}
LL ans1=S1[ma1]-S2[mi];
int mi1=-1;
if(mi>l)
mi1=T2.query(l,mi-1);
if(mi<r)
{
int u=T2.query(mi+1,r);
if(mi1==-1||(-S2[mi1])<(-S2[u]))mi1=u;
}
LL ans2=S1[ma]-S2[mi1];
printf("%lld\n",max(ans1,ans2));
}
else
printf("%lld\n",S1[ma]-S2[mi]);
}
return 0;
}