codevs 3304 水果姐逛水果街Ⅰ

–昨天晚上没有调完我的线段树做法,今天才来,感觉这个题正解可能就是线段树吧,前面称之为DP的方法有点扯,但是能过啊,能过就好QAQ
*题目链接:http://codevs.cn/problem/3304/
–在查询时,因为要同时返回最大值,最小值和答案三个值,所以可以定义一个结构体型的Ask函数,这样就不用再单独写Ask_max和Ask_min函数了,省时省力
–注意每次返回一个Ask函数时,都要把答案和右(左)区间的最大值减左(右)区间的最小值的值比较一下;
代码:

#include
#include
#include
#include
#include
using namespace std;

const int maxn=2e5+10,inf=1e8+10;
int n,m,Ans;
int a[maxn];
struct hh
{
    int l,r;
    int maxx,minn,ans1,ans2;
}tree[maxn<<2];
struct lxt
{
    int ma,mi,ans;
};

void build(int l,int r,int i)
{
    tree[i].l=l;
    tree[i].r=r;
    if(l==r) 
    {
        tree[i].minn=tree[i].maxx=a[l];
        tree[i].ans1=tree[i].ans2=0;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    tree[i].minn=min(tree[i<<1].minn,tree[i<<1|1].minn);
    tree[i].maxx=max(tree[i<<1].maxx,tree[i<<1|1].maxx);
    tree[i].ans1=max(tree[i<<1|1].maxx-tree[i<<1].minn,max(tree[i<<1|1].ans1,tree[i<<1].ans1));
    tree[i].ans2=max(tree[i<<1].maxx-tree[i<<1|1].minn,max(tree[i<<1|1].ans2,tree[i<<1].ans2));
    if(tree[i].ans1<0) tree[i].ans1=0;
    if(tree[i].ans2<0) tree[i].ans2=0;
}
lxt ask_one(int l,int r,int i)
{
    lxt f;
    f.ans=0;
    f.mi=inf;
    f.ma=-inf;
    int lx=tree[i].l,rx=tree[i].r;
    if(lx>=l&&rx<=r)
    {
        f.ans=tree[i].ans1;
        f.ma=tree[i].maxx;
        f.mi=tree[i].minn;
        return f;
    }
    int mid=(lx+rx)>>1;
    lxt A,B;
    if(l<=mid) 
    {
        A=ask_one(l,r,i<<1); 
        f.ans=max(f.ans,A.ans);
        f.mi=min(f.mi,A.mi);
        f.ma=max(f.ma,A.ma);
    }
    if(r>mid) 
    {
        B=ask_one(l,r,i<<1|1);
        f.ans=max(f.ans,B.ans);
        f.mi=min(f.mi,B.mi);
        f.ma=max(f.ma,B.ma);
    }
    if(l<=mid&&r>mid) 
      f.ans=max(f.ans,B.ma-A.mi);
    return f;
}
lxt ask_two(int l,int r,int i)
{
    lxt f;
    f.ans=0;
    f.mi=inf;
    f.ma=-inf;
    int lx=tree[i].l,rx=tree[i].r;
    if(lx>=l&&rx<=r)
    {
        f.ans=tree[i].ans2;
        f.ma=tree[i].maxx;
        f.mi=tree[i].minn;
        return f;
    }

    int mid=(lx+rx)>>1;
    lxt A,B;
    if(l<=mid) 
    {
        A=ask_two(l,r,i<<1); 
        f.ans=max(f.ans,A.ans);
        f.mi=min(f.mi,A.mi);
        f.ma=max(f.ma,A.ma);
    }
    if(r>mid) 
    {
        B=ask_two(l,r,i<<1|1);
        f.ans=max(f.ans,B.ans);
        f.mi=min(f.mi,B.mi);
        f.ma=max(f.ma,B.ma);
    }
    if(l<=mid&&r>mid) 
      f.ans=max(f.ans,A.ma-B.mi);
    return f;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Ans=0;
        if(x<y) Ans=ask_one(x,y,1).ans;
        else if(x>y) Ans=ask_two(y,x,1).ans;
        printf("%d\n",Ans);
    }
    return 0;
}

你可能感兴趣的:(===数据结构===,线段树)