codeforces 91b Queue

http://codeforces.com/problemset/problem/91/B


题意是给你一个数组,对每个数求它最右的一个比他小的数和他的距离。

 

考虑二分该数右边的区间,先求(mid,r)的最小值,如果小于该数就接着二分

区间最小值用线段树维护。


#include <iostream>
#include <climits>

using namespace std;

const int MAXN=100010;

int num[MAXN];

template<class T>struct Segtree {
#define ls (o<<1)
#define rs (o<<1)|1
    T data[MAXN<<2];
    void pushup(int o) {
        data[o]=min(data[ls],data[rs]);
    }
    void build(int o,int l,int r) {
        if(l==r) {
            data[o]=num[l];
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        pushup(o);
    }

    T query(int o,int l,int r,int x,int y) {
        if(l>=x && r<=y) {
            return data[o];
        }
        int mid=(l+r)>>1;
        if(y<=mid) return query(ls,l,mid,x,y);
        if(x>mid)  return query(rs,mid+1,r,x,y);
        return min(query(ls,l,mid,x,y),query(rs,mid+1,r,x,y));
    }
};

Segtree<int> tree;

int n;
int ans[MAXN];

int solve (int x,int t) {
    int l=x,r=n;
    while(r-l>=3){
        int mid=(l+r)>>1;
       // cout<<"mid= "<<mid<<endl;
        if(tree.query(1,1,n,mid,r)<t){
            l=mid;
            continue;
        }
        if(tree.query(1,1,n,l,mid)<t){
            r=mid;
            continue;
        }
        break;
    }
   // cout<<l<<' '<<r<<endl;
    if(r-l>=3)
        return -1;
    int ans=0;
    for(int i=r;i>=l;i--){
        if(num[i]<t){
            ans=i;
            break;
        }
    }
    if(ans==0)
        return -1;
    ans=ans-x-1;
    return ans;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>num[i];
    }
    tree.build(1,1,n);
    for(int i=1;i<=n;i++){
     //   cout<<"i= "<<i<<endl;
        ans[i]= solve(i,num[i]);
    }
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<' ';
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值