2019.03.09 bzoj4491: 我也不知道题目名字是什么(线段树)

时间:2022-08-02 17:52:18

传送门

题意:给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串。


思路:

注意要求的是子串而不是子序列!!!

然后直接用线段树维护最大子段和的方式合并一下就完了。

注意要维护当前区间最靠左/右的数是什么。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
const int N=50005;
int n,a[N];
inline int max(const int&a,const int&b){return a>b?a:b;}
inline int max(const int&a,const int&b,const int&c){return a>b?(a>c?a:c):(b>c?b:c);}
namespace SGT{
    #define lc (p<<1)
    #define rc (p<<1|1)
    #define mid (l+r>>1)
    struct Val{
        int L,R,len,ls[2],rs[2],ms[2];
        friend inline Val operator+(const Val&a,const Val&b){
            Val ret;
            ret.L=a.L,ret.R=b.R,ret.len=a.len+b.len;
            ret.rs[0]=b.rs[0]+(b.rs[0]==b.len&&a.R<=b.L?a.rs[0]:0);
            ret.rs[1]=b.rs[1]+(b.rs[1]==b.len&&a.R>=b.L?a.rs[1]:0);
            ret.ls[0]=a.ls[0]+(a.ls[0]==a.len&&a.R<=b.L?b.ls[0]:0);
            ret.ls[1]=a.ls[1]+(a.ls[1]==a.len&&a.R>=b.L?b.ls[1]:0);
            ret.ms[0]=max(a.ms[0],b.ms[0],a.R<=b.L?a.rs[0]+b.ls[0]:0);
            ret.ms[1]=max(a.ms[1],b.ms[1],a.R>=b.L?a.rs[1]+b.ls[1]:0);
            return ret;
        }
        inline void Set(const int&x){L=R=x,len=ls[0]=rs[0]=ms[0]=ls[1]=rs[1]=ms[1]=1;}
    };
    struct Node{int l,r;Val val;}T[N<<2];
    inline void pushup(int p){T[p].val=T[lc].val+T[rc].val;}
    inline void build(int p,int l,int r){
        T[p].l=l,T[p].r=r;
        if(l==r)return T[p].val.Set(a[l]);
        build(lc,l,mid),build(rc,mid+1,r),pushup(p);
    }
    inline Val query(int p,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return T[p].val;
        if(qr<=mid)return query(lc,l,mid,ql,qr);
        if(ql>mid)return query(rc,mid+1,r,ql,qr);
        return query(lc,l,mid,ql,mid)+query(rc,mid+1,r,mid+1,qr);
    }
    #undef lc
    #undef rc
    #undef mid
}
int main(){
    n=read();
    for(ri i=1;i<=n;++i)a[i]=read();
    SGT::build(1,1,n);
    SGT::Val tmp;
    for(ri tt=read(),l,r;tt;--tt){
        l=read(),r=read(),tmp=SGT::query(1,1,n,l,r);
        cout<<max(tmp.ms[0],tmp.ms[1])<<'\n';
    }
    return 0;
}