51nod 1593 公园晨跑

来源:互联网 发布:废铁战士淘宝可靠吗 编辑:程序博客网 时间:2024/04/30 16:00

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作为猴子选择的两个棵树的编号,那么它消耗的能量为:

dxdy+2hx+2hy

x<y

dxdy+2hx+2hy=dydx+2hx+2hy=(dy+2hy)(dx2hx)

令 :

A[x]=dx+2hxB[x]=dx2hx

原问题等价于计算,指定区间[L,R]内:

maxx,y[L,R]  ,    xy(A[x]B[y])

假设 x=X,y=Y时 有:

maxx[L,R]A[x]=A[X]miny[L,R]B[y]=B[Y]

XY时:

maxx,y[L,R]  ,    xy(A[x]B[y])=A[X]B[Y]

X=Y时:

假设有 满足下面等式的a,b

maxx,y[L,R]  ,    xy(A[x]B[y])=A[a]B[b]

如果 aXbY,又因为 ,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],yYB[y]

b=Y时的答案,有:

A[a]=maxx[L,R],xXB[x]

#include <stdio.h>#include <algorithm>#include <string.h>#define MAXN 300005using 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;}
原创粉丝点击