LA3938(线段树)求区间最值范围

本题思想并不复杂,比较麻烦的在于细节部分的处理,对于一些情况是否使用等于对于题目有不同的情况。

首先题目开始要求求出范围内最大值的左端点右端点,因此再遍历时需要对于端点进行更新因此设计上较为复杂。

对于最大值存在两种情况,可能时在M左侧或M右侧或者左右端点在M两侧,因此对于题目的要求我们需要对不同的情况进行不同的讨论。

代码如下

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define mem(x) (memset(x,0,sizeof(x)))
typedef vector<int> VI;
typedef long long lll;
typedef pair<int,int> PII;
typedef double db;
mt19937 mrand(random_device{}());
const lll mod=1000000007;
int rnd(int x) { return mrand() % x;}
lll powmod(lll a,lll b) {lll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
lll gcd(lll a,lll b) { return b?gcd(b,a%b):a;}
int n,m;
const int maxn=500005;
#define mid int M=L+(R-L)/2;
#define ls o*2
#define rs o*2+1
struct node
{
    lll num,sum,lsum,rsum; //num为最大值,sum为和,lsum为最大前缀和,rsum为最大后缀和
    int l,r,ll,rr;  //l,r为最大区间左右端点 ll,rr为最大前后缀端点
}a[maxn<<2];

void update(int o,int L,int R)
{
    mid;
    //if(o==4)
       // cout<<a[o].l<<a[o].r<<"%%";
    a[o].sum=a[ls].sum+a[rs].sum;
    a[o].lsum=a[ls].lsum;a[o].rsum=a[rs].rsum;
    a[o].ll=a[ls].ll;a[o].rr=a[rs].rr;
    if(a[o].lsum<a[ls].sum+a[rs].lsum)
    {
        a[o].lsum=a[ls].sum+a[rs].lsum;
        a[o].ll=a[rs].ll;
    }
    if(a[o].rsum<=a[rs].sum+a[ls].rsum)
    {
        a[o].rsum=a[ls].rsum+a[rs].sum;
        a[o].rr=a[ls].rr;
    }
    node tp;
    if(a[ls].num>=a[rs].num)
        tp=a[ls];
    else
        tp=a[rs];
    a[o].num=tp.num;a[o].l=tp.l;a[o].r=tp.r;
    lll ans=a[ls].rsum+a[rs].lsum;
    if(ans>a[o].num||ans==a[o].num&&a[o].l>a[ls].rr||
       a[o].num==ans&&a[o].l==a[ls].rr&&a[o].r>a[rs].ll)
    {
        a[o].num=ans;a[o].l=a[ls].rr;a[o].r=a[rs].ll;
    }
    return ;

}
void build(int o=1,int L=1,int R=n)
{
    if(L==R)
    {
        scanf("%lld",&a[o].sum);
       // cout<<L<<a[o].sum;
        a[o].rsum=a[o].lsum=a[o].num=a[o].sum;
        a[o].r=a[o].rr=a[o].l=a[o].ll=L;
       // if(o==4)
         //   cout<<a[o].r<<a[o].l;
        return ;
    }
    mid;
    //cout<<L<<R<<M;
    build(ls,L,M);
    build(rs,M+1,R);
    update(o,L,R);
}
node query(int l,int r,int o=1,int L=1,int R=n)
{
    if(l==L&&r==R)
    {
      //  cout<<l<<o<<a[o].l;
        return a[o];
    }
        mid;
        if(r<=M)
        {
            return query(l,r,ls,L,M);
        }
        else if(l>M)
        {
            return query(l,r,rs,M+1,R);
        }
        else
        {
            node t1=query(l,M,ls,L,M);
            node t2=query(M+1,r,rs,M+1,R);
            node ret;
            ret.sum=t1.sum+t2.sum;
            if(t1.num>=t2.num)
            {
                ret=t1;
            }
            else
                ret=t2;
            lll ans=t1.rsum+t2.lsum;
            if(ans>ret.num||ans==ret.num&&t1.rr<ret.l
               ||ans==ret.num&&t1.rr==ret.l&&t2.ll<ret.r)
            {
                ret.num=ans;ret.l=t1.rr;ret.r=t2.ll;
            }
            ret.lsum=t1.lsum;ret.rsum=t2.rsum;
            ret.ll=t1.ll;ret.rr=t2.rr;
            if(ret.lsum<t1.sum+t2.lsum)
                ret.lsum=t1.sum+t2.lsum,ret.ll=t2.ll;
            if(ret.rsum<=t2.sum+t1.rsum)
                ret.rsum=t1.rsum+t2.sum,ret.rr=t1.rr;
              //  cout<<ret.l<<ret.r<<endl;
            return ret;
        }
}
// head
int main()
{
    int cas=1;
   // ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    while(~scanf("%d %d",&n,&m))
    {
        build();
        printf("Case %d:\n",cas++);
        int x,y;
        rep(i,0,m)
        {
            scanf("%d %d",&x,&y);
            node t=query(x,y);
            printf("%d %d\n",t.l,t.r);
        }
    }

}

 

posted @ 2021-03-06 16:15  大抵一个菜鸡而已  阅读(67)  评论(0编辑  收藏  举报