[倍增] Jzoj P6279 优美序列
题解
- 倍增维护区间最大最小值,维护坐标做小最大值
- 然后就可以在倍增上查询包含该区间的完美序列的坐标的做大做小值
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 const int N=1e5+10,M=30; 7 int n,m,mi[M],mx[N][M],mn[N][M],Mx[N][M],Mn[N][M],p[N],a[N]; 8 int querymx(int x,int y) { int k=p[y-x+1]; return max(mx[x][k],mx[y-mi[k]+1][k]); } 9 int querymn(int x,int y) { int k=p[y-x+1]; return min(mn[x][k],mn[y-mi[k]+1][k]); } 10 int queryMx(int x,int y) { int k=p[y-x+1]; return max(Mx[x][k],Mx[y-mi[k]+1][k]); } 11 int queryMn(int x,int y) { int k=p[y-x+1]; return min(Mn[x][k],Mn[y-mi[k]+1][k]); } 12 int main() 13 { 14 freopen("sequence.in","r",stdin),freopen("sequence.out","w",stdout); 15 scanf("%d",&n); for (int i=0;i<=20;i++) mi[i]=1<<i; 16 for (int i=1;i<=n;i++) scanf("%d",&a[i]),mx[i][0]=mn[i][0]=a[i],Mx[a[i]][0]=Mn[a[i]][0]=i,p[i]=(int)log2(i); 17 for (int i=n-1;i>=1;i--) for (int j=1;i+mi[j]-1<=n;j++) 18 mx[i][j]=max(mx[i][j-1],mx[i+mi[j-1]][j-1]),Mx[i][j]=max(Mx[i][j-1],Mx[i+mi[j-1]][j-1]),mn[i][j]=min(mn[i][j-1],mn[i+mi[j-1]][j-1]),Mn[i][j]=min(Mn[i][j-1],Mn[i+mi[j-1]][j-1]); 19 scanf("%d",&m); 20 for (int l,r,L,R,flag,boo,num,Max,Min;m;m--) 21 { 22 scanf("%d%d",&l,&r),L=R=flag=boo=num=0; 23 while (l!=L||r!=R) 24 { 25 num++; 26 if (num>70) { flag=1; break; } 27 if (boo) l=L,r=R; 28 Max=querymx(l,r),Min=querymn(l,r),L=queryMn(Min,Max),R=queryMx(Min,Max); 29 if (!boo) boo=1; 30 } 31 if (flag==1) 32 { 33 int i; 34 for (i=min(5,l);i>=1;i--) { Max=querymx(i,n),Min=querymn(i,n); if (Max-Min==n-i) break; } 35 printf("%d %d\n",i,n); 36 }else printf("%d %d\n",l,r); 37 } 38 }