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\n",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\n",ans); } } }