CF91B Queue

CF91B Queue

洛谷传送门

题意翻译

  • 给定 nnn 个正整数 a1…na_{1 dots n}a1…n。

  • 需要输出一行 nnn 个数,设此时正在处理第 iii 个数:

    • 设 aj<aia_j<a_iaj<ai 且 j>ij >ij>i。
    • 在满足第一条的基础上使 j−i−1j-i-1j−i−1 尽可能大,此时 j−i−1j-i-1j−i−1 即为答案。
  • 2≤n≤105,ai≤1092 leq n leq 10^5,a_i leq 10^92≤n≤105,ai≤109,如果对于某个 iii,没有任何一个 jjj 满足 aj<aia_j<a_iaj<ai 且 j>ij>ij>i,输出 -1


题解:

首先概括题意:要求一个序列每一个位置最右侧的比自己小的数是谁。没有输出-1.

发现完全可以用线段树处理,维护一个区间最小值的线段树,查询的时候返回位置,每次优先查询右面。

有人说这叫线段树上二分,我觉得线段树本身就是二分的一个结构,所以不太算吧。

那么就直接上代码吧:

#include<cstdio>
#include<algorithm>
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=1e5+5;
int n;
int a[maxn];
int mn[maxn<<2];
void build(int pos,int l,int r)
{
    int mid=(l+r)>>1;
    if(l==r)
    {
        mn[pos]=a[l];
        return;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    mn[pos]=min(mn[lson],mn[rson]);
}
int query(int pos,int l,int r,int x,int y,int k)//查询x-y区间中下标最大的小于k的数的下标
{
    int mid=(l+r)>>1;
    int ret=0;
    if(mn[pos]>=k)
        return -1;
    if(l==r)
        return l;
    if(y>mid)
    {
        ret=query(rson,mid+1,r,x,y,k);
        if(ret!=-1)
            return ret;
    }
    if(x<=mid)
        ret=query(lson,l,mid,x,y,k);
    return ret;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<n;i++)
    {
        int ans=query(1,1,n,i+1,n,a[i]);
        if(ans==-1)
            printf("%d ",ans);
        else 
            printf("%d ",ans-i-1);
    }
    printf("-1");
    return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/14015615.html