BZOJ 4491 分块OR差分+线段树

思路:

(是不是只有我作大死写了个分块)

up[i][j]表示从第i块开始到第j个位置 上升的最大值

down[i][j]同理

left_up[i]表示从第i块开始能够上升的最长长度

left_down[i]同理

right_up[i]表示从第i块结尾上升的最长长度

right_down[i]同理

然后就是各种恶心的分类讨论

(见代码吧,,,,,,)

嗯这道题还可以差分以后线段树维护>0的最长长度(左max 右max 区间max)

//By SiriusRen
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=50050,inf=0x3f3f3f3f;
int n,q,l,r,a[N],block[N],up[230][N],down[230][N],left_up[230],left_down[230],right_up[230],right_down[230];
int main(){
    scanf("%d",&n);int Block=sqrt(n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)block[i]=(i-1)/Block+1;
    for(int i=1;i<=block[n];i++){
        int temp_up=1,temp_down=1,f_up=0,f_down=0;
        for(int j=lower_bound(block+1,block+1+n,i)-block;j<=n;j++){
            up[i][j]=max(up[i][j-1],temp_up),down[i][j]=max(temp_down,down[i][j-1]);
            if(!f_down)left_down[i]=temp_down;
            if(!f_up)left_up[i]=temp_up;
            if(a[j+1]>a[j])temp_up++,temp_down=1,f_down=1;
            else if(a[j+1]<a[j])temp_down++,temp_up=1,f_up=1;
            else temp_up++,temp_down++;
        }
    }
    for(int i=1;i<=block[n];i++){
        int temp=lower_bound(block+1,block+1+n,i)-block,j=upper_bound(block+1,block+1+n,i)-block-1,temp_up=1,temp_down=1;
        for(;block[j]==block[temp];j--){
            right_up[i]=max(right_up[i],temp_up),right_down[i]=max(right_down[i],temp_down);
            if(a[j-1]>a[j])temp_up++,temp_down=-inf;
            else if(a[j-1]<a[j])temp_down++,temp_up=-inf;
            else temp_up++,temp_down++;
        }
    }
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&l,&r);
        if(block[l]==block[r]){
            int ans=0;
            int temp_up=1,temp_down=1;
            for(int j=l;j<=r;j++){
                ans=max(ans,max(temp_up,temp_down));
                if(a[j+1]>a[j])temp_up++,temp_down=1;
                else if(a[j+1]<a[j])temp_down++,temp_up=1;
                else temp_up++,temp_down++;
            }
            printf("%d
",ans);
        }
        else{
            int L=block[l]+1,ans=max(up[L][r],down[L][r]),temp_up=1,temp_down=1;
            int beginL=lower_bound(block+1,block+1+n,L)-block;
            for(int j=l;j<beginL;j++){
                ans=max(ans,max(temp_up,temp_down));
                if(a[j+1]>a[j])temp_up++,temp_down=1;
                else if(a[j+1]<a[j])temp_down++,temp_up=1;
                else temp_up++,temp_down++;
            }
            if(a[beginL]>=a[beginL-1]){
                int tmpx=min(right_down[L-1],beginL-l),tmpy=min(r-beginL+1,left_up[L]);
                ans=max(ans,tmpx+tmpy);
            }
            if(a[beginL]<=a[beginL-1]){
                int tmpx=min(right_up[L-1],beginL-l),tmpy=min(r-beginL+1,left_down[L]);
                ans=max(ans,tmpx+tmpy);
            }
            printf("%d
",ans);
        }
    }
}
原文地址:https://www.cnblogs.com/SiriusRen/p/6556423.html