Live2D

[线段树] (j) uva1400* (区间查询和定位尝试)(难题)

uva1400 "Ray, Pass me the dishes!"

如在阅读本文时遇到不懂的部分,请在评论区询问,或跳转 线段树总介绍

 

这题在luogu上是黑题呢...QAQ(但是却是一道线段树模版题啊qwq)

 

题目大意:给出一个长度为n的整数序列D,对m个询问做出回答,对询问(a,b)找到(x,y)使得a<=x<=y<=b且Dx+Dx+1+……+Dy最大。如有多组答案取字典序最小的一组(即x,y最小)。

 

下面是无关紧要的一点废话(一点一点的解释代码)

 

因为要输出两个数(x,y)显然不能用普通的返回值了,那么这里选择用一个结构体类型data来作返回值,其l,r就是要求的x,y

为了能够比较大小(字典序)又写了 彩虹般的 重载运算符,友元函数。(也可以使用pair)

又用了前缀和sum[]来进行优化。

 

要注意的是如果用重载运算符,可以选择定义一个val或者用前缀和,

但是如果用pair,则一定要写重载运算符(因为不能有三个量)。

 

当然你也可以选择手动写个比较函数

struct data{
    int l,r;
    long long val(){return sum[r]-sum[l-1];}
    friend bool operator > (data a,data b){
        return a.val()>b.val()||(a.val()==b.val()&&(a.l<b.l||(a.l==b.l&&a.r<b.r)));
    }
    friend bool operator < (data a,data b){
        return a.val()<b.val()||(a.val()==b.val()&&(a.l>b.l||(a.l==b.l&&a.r>b.r)));
    }
};

 

 

defmax是一个data型的max....

data defmax(data a,data b){
    return a>b?a:b;
}

 

大概写成这样会更好?(那就什么类型都能用啦...woc难道还要比较其他类型吗?)

auto defmax(auto a,auto b){
  return  a>b?a:b;  
}

 

pushup:

Maxn比较左、右、中间

pre比较左、左+右

suf同理

void pushup(int rt){
        Maxn[rt]=defmax(defmax(Maxn[LS],Maxn[RS]),(data){suf[LS].l,pre[RS].r});
        //left right and middle
        pre[rt]=defmax(pre[LS],(data){pre[LS].l,pre[RS].r});
        suf[rt]=defmax(suf[RS],(data){suf[LS].l,suf[RS].r});
        //注意此处要看大小而不是区间长度
    }

 

build,就是build

 void build(int rt,int l,int r){
        if(l==r){
            pre[rt]=suf[rt]=Maxn[rt]=(data){l,r};
            return;
        }int mid=l+r>>1;
        build(LS,l,mid);
        build(RS,mid+1,r);
        pushup(rt); return;
    }

 

query

如果包含 直接返回该节点的最大区间

不在区间内判断左右(整区间)

在中间 在左边找后继右边找前驱并拼凑,与纯左、纯右对比取大

  data query(int rt,int l,int r,int x,int y){
        if(x<=l&&y>=r)return Maxn[rt];
        int mid=l+r>>1;
        if(y<=mid) //左儿子
            return query(LS,l,mid,x,y);
        if(x>mid)  //右儿子
            return query(RS,mid+1,r,x,y);
        //在中间
        data a=defmax(query(LS,l,mid,x,y),query(RS,mid+1,r,x,y));
        data b=(data){asksuf(LS,l,mid,x,y).l,askpre(RS,mid+1,r,x,y).r};
        return defmax(a,b);
    }

 

找前驱/后继(对称版)

后继一直往右找,前驱往左找,保证最后正好拼凑起来

    data asksuf(int rt,int l,int r,int x,int y){ //在左子树内找后继(r == y)
        if(suf[rt].l>=x)return suf[rt]; //此区间后继一定 > 儿子后继
        int mid=l+r>>1;
        if(x>mid)return asksuf(RS,mid+1,r,x,y);
        return defmax((data){asksuf(LS,l,mid,x,y).l,r},suf[RS]);
    }
    data askpre(int rt,int l,int r,int x,int y){
        if(pre[rt].r<=y)return pre[rt];
        int mid=l+r>>1;
        if(y<=mid)return askpre(LS,l,mid,x,y);
        return defmax((data){l,askpre(RS,mid+1,r,x,y).r},pre[LS]);
    }

 

 

代码

 

QAQ friend竟然没有高亮,自己加了个生态环保绿

/*uva1400*/
#include<iostream> #include<cmath> #include<algorithm> #include<cstdio> using namespace std; const int N=2e6+3; long long sum[N],a[N]; struct data{ int l,r; long long val(){return sum[r]-sum[l-1];} friend bool operator > (data a,data b){ return a.val()>b.val()||(a.val()==b.val()&&(a.l<b.l||(a.l==b.l&&a.r<b.r))); } friend bool operator < (data a,data b){ return a.val()<b.val()||(a.val()==b.val()&&(a.l>b.l||(a.l==b.l&&a.r>b.r))); } }; data defmax(data a,data b){ return a>b?a:b; } namespace Segment_Tree{ #define LS (rt<<1) #define RS (LS|1) data pre[N<<2],suf[N<<2],Maxn[N<<2]; //前驱 后继 最大子段和 void pushup(int rt){ Maxn[rt]=defmax(defmax(Maxn[LS],Maxn[RS]),(data){suf[LS].l,pre[RS].r}); //left right and middle pre[rt]=defmax(pre[LS],(data){pre[LS].l,pre[RS].r}); suf[rt]=defmax(suf[RS],(data){suf[LS].l,suf[RS].r}); //注意此处要看大小而不是区间长度 } void build(int rt,int l,int r){ if(l==r){ pre[rt]=suf[rt]=Maxn[rt]=(data){l,r}; return; }int mid=l+r>>1; build(LS,l,mid); build(RS,mid+1,r); pushup(rt); return; } data asksuf(int rt,int l,int r,int x,int y){ //在左子树内找后继(r == y) if(suf[rt].l>=x)return suf[rt]; //此区间后继一定 > 儿子后继 int mid=l+r>>1; if(x>mid)return asksuf(RS,mid+1,r,x,y); return defmax((data){asksuf(LS,l,mid,x,y).l,r},suf[RS]); } data askpre(int rt,int l,int r,int x,int y){ if(pre[rt].r<=y)return pre[rt]; int mid=l+r>>1; if(y<=mid)return askpre(LS,l,mid,x,y); return defmax((data){l,askpre(RS,mid+1,r,x,y).r},pre[LS]); } data query(int rt,int l,int r,int x,int y){ if(x<=l&&y>=r)return Maxn[rt]; int mid=l+r>>1; if(y<=mid) //左儿子 return query(LS,l,mid,x,y); if(x>mid) //右儿子 return query(RS,mid+1,r,x,y); //在中间 data a=defmax(query(LS,l,mid,x,y),query(RS,mid+1,r,x,y)); data b=(data){asksuf(LS,l,mid,x,y).l,askpre(RS,mid+1,r,x,y).r}; return defmax(a,b); } } using namespace Segment_Tree; int main(){ int n,m,x,y,Case=0; data ans; while(scanf("%d%d", &n, &m)!=EOF){ printf("Case %d:\n",++Case); for(int i=1;i<=n;++i){ scanf("%lld",&a[i]); sum[i]=a[i]+sum[i-1]; //sum会覆盖以前的,可以不初始化 } build(1,1,n); while(m--){ scanf("%d%d",&x,&y); ans=query(1,1,n,x,y); printf("%d %d\n",ans.l,ans.r); } } return 0; }

 

posted @ 2019-07-23 01:17  lsy263  阅读(204)  评论(0编辑  收藏  举报