给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
标签:
给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
第一行n,表示A数组有多少元素
接下来一行为n个整数A[i]
接下来一个整数Q,表示询问数量
接下来Q行,每行2个整数l,r
对于每个询问,求[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\n",mx[pv]); } return 0; }
标签:
原文地址:http://www.cnblogs.com/ccz181078/p/5358883.html