牛客练习赛85 C 哲学家的沉思 尺取 单调递增子序列 倍增
题意:
每次询问一个区间,求这个区间最长单调递增子序列的长度
题解:
赛时想到了尺取预处理,从当前的点开始第一个高度大于它的点的位置
然后就没有然后了
赛后看题解,用的方法是倍增,具体方法是,维护一个数组st[j][i]
代表从j点开始,跳$2^i$次能到哪个点
这样的话每次询问复杂度就到了log n
AC代码(非本人原创):
#include<bits/stdc++.h> using namespace std; int a[100005],rr[100005],st[100005][20]; int main() { int i,j,n,q,l,r,ans; scanf("%d%d",&n,&q); for(i=1;i<=n;i++)scanf("%d",&a[i]); st[n][0]=rr[n]=n+1; for(i=n-1;i>=1;i--) { for(j=i+1;j!=n+1&&a[j]<=a[i];j=rr[j]); rr[i]=st[i][0]=j; } for(i=1;i<=17;i++) { for(j=1;j<=n;j++) { if(st[j][i-1]>n)st[j][i]=1e9; else st[j][i]=st[st[j][i-1]][i-1]; } } while(q--) { scanf("%d%d",&l,&r),ans=0; for(i=17;i>=0;i--)if(st[l][i]<=r)l=st[l][i],ans|=(1<<i); printf("%d\n",ans+1); } }
另外,有人说是CF1516D的弱化版,条件从两两互质变成了左边的最大