bzoj4491 我也不知道题目名字是什么

Description

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

Input

第一行n,表示A数组有多少元素
接下来一行为n个整数A[i]
接下来一个整数Q,表示询问数量
接下来Q行,每行2个整数l,r

Output

对于每个询问,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串

用线段树维护区间最长单调子串长度、左右端点值、接触左右端的最长单调非减/非增子串长度,可以很方便地合并区间信息

#include<cstdio>
inline int read(){
    int x=0,c=getchar(),f=1;
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
    return x*f;
}
const int N=132000;
int p,pv;
int n,q;
int lv[N],rv[N],mx[N],li[N],ld[N],ri[N],rd[N],sz[N],l,r;
inline int max(int a,int b){return a>b?a:b;}
inline void upd(int w,int lc,int rc){
    sz[w]=sz[lc]+sz[rc];
    mx[w]=max(mx[lc],mx[rc]);
    lv[w]=lv[lc];rv[w]=rv[rc];
    li[w]=li[lc];ld[w]=ld[lc];
    ri[w]=ri[rc];rd[w]=rd[rc];
    if(rv[lc]<=lv[rc]){
        mx[w]=max(mx[w],ri[lc]+li[rc]);
        if(li[lc]==sz[lc])li[w]=max(li[w],li[lc]+li[rc]);
        if(ri[rc]==sz[rc])ri[w]=max(ri[w],ri[lc]+ri[rc]);
    }
    if(rv[lc]>=lv[rc]){
        mx[w]=max(mx[w],rd[lc]+ld[rc]);
        if(ld[lc]==sz[lc])ld[w]=max(ld[w],ld[lc]+ld[rc]);
        if(rd[rc]==sz[rc])rd[w]=max(rd[w],rd[lc]+rd[rc]);
    }
}
void get(int w=1,int L=1,int R=65536){
    if(l<=L&&R<=r){
        if(pv){
            upd(p,pv,w);
            pv=p++;
        }else pv=w;
        return;
    }
    int M=L+R>>1;
    if(l<=M)get(w<<1,L,M);
    if(r>M)get(w<<1^1,M+1,R);
}
int main(){
    n=read();
    for(int i=1;i<=n;++i){
        int u=i+65535;
        lv[u]=rv[u]=read();
        mx[u]=sz[u]=li[u]=ld[u]=ri[u]=rd[u]=1;
    }
    for(int i=65535;i;--i){
        int lc=i<<1,rc=lc^1;
        upd(i,lc,rc);
    }
    q=read()+1;
    while(--q){
        l=read();r=read();
        p=131072;pv=0;
        get();
        printf("%d
",mx[pv]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5358883.html