牛客练习赛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
",ans+1);
    }
}

另外,有人说是CF1516D的弱化版,条件从两两互质变成了左边的最大

原文地址:https://www.cnblogs.com/isakovsky/p/14932895.html