Codeforces Beta Round #75 (Div. 1 Only) B. Queue 线段树。单点更新

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

题意:

给你n个数,求得i 到n中小于a[i]的最右边的a[j],然后求a[i]到a[j]之间包含了多少个数。

思路:

首先自己在做这道题的时候没有认真读题,直接把题意搞成求得i 到n中小于a[i]的最右边的a[j],然后求a[i]到a[j]之间包含了多少个小于a[i]的数了。。。结果样例都没过。唉自己还是太粗心,一定要认真把题意搞清楚,然后把想法想好了再敲。不过也算是做了另一道题目吧。

首先我的思路,好像比较复杂。 我们利用线段树维护小于a[i]的区间[1,a[i]]的最大坐标值,当然要将数列离散话,因为a[i]最大为10^9 而n最大是10^5 .每次插入数据更新区间最值,然后就是求出该区间最值与当前坐标比较求个数。

View Code
By E_star, contest: Codeforces Beta Round #75 (Div. 1 Only), problem: (B) Queue, Accepted, #
 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 1000007
#define N 1000007
using namespace std;
//freopen("data.in","r",stdin);

struct node{
    int val;
    int pos;
}a[N];
int X[N];
int val[N*4];
int pos[N];

void pushup(int rt){
    val[rt] = max(val[rt<<1],val[rt<<1|1]);
}
void update(int pos,int sc,int l,int r,int rt){
    if (l == r){
        val[rt] = sc;
        return ;
    }
    int m = (l + r)>>1;
    if (pos <= m) update(pos,sc,lc);
    else update(pos,sc,rc);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
    if (l >= L && r <= R){
        return val[rt];
    }
    int res = 0;
    int m = (l + r)>>1;
    if (L <= m) res = max(res,query(L,R,lc));
    if (R > m) res = max(res,query(L,R,rc));
    return res;
}
int bSearch(int p,int L,int R){
    int l = L;
    int r = R;
    int ans = 0;
    while (l <= r){
        int m = (l + r)>>1;
        if (X[m] <= p){
            l = m + 1;
            ans = m;
        }
        else{
            r = m  - 1;
        }
        //puts("<<<<");
    }
    return ans;
}

int main(){
    //freopen("data.in","r",stdin);
    int i;
    int n;
    while (~scanf("%d",&n)){
        for (i = 1; i <= n; ++i){
            scanf("%d",&a[i].val);
            a[i].pos = i;
            X[i] = a[i].val;
        }
       //离散化
        sort(X + 1,X + 1 + n);
        int k = 1;
        for (i = 2; i <= n; ++i){
            if (X[i] != X[i - 1]) X[++k] = X[i];
        }
        //每插进一个点就更新[1,a[i]]区间最值
        CL(val,0);
        for (i = 1; i <= n; ++i){
            pos[i] = bSearch(a[i].val,1,k);
            update(pos[i],a[i].pos,1,k,1);
        }
       
        for (i = 1; i < n; ++i){
            int p = bSearch(a[i].val - 1,1,k);//二分查找第一个小于a[i]的值
            if (p == 0){
                printf("-1 ");
                continue;
            }
            int ans = query(1,p,1,k,1);//询问该区间的最大坐标
            if (ans <= a[i].pos) printf("-1 ");
            else{
                ans = ans - a[i].pos - 1;
                printf("%d ",ans);
            }
        }
        printf("-1\n");
    }
    return 0;
}     

 

别人的思路,思考方向不一样,做法就不一样。我觉得这个想法很简洁明了。他直接记录区间最值,枚举每个a[i]每次把枚举到的a[i]更新成inf,线段树求出整个区间最小值,与该值比较,如果大于等于它肯定输出-1,否则线段树里求右边第一个小于a[i]的值的坐标。 (这里最巧妙数的求最右边第一个小于a[i]的坐标,以前没接触过这个求法)

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 1000007
#define N 1000007
using namespace std;
//freopen("data.in","r",stdin);

int a[N],val[N];

void pushup(int rt){
    val[rt] = min(val[rt<<1],val[rt<<1|1]);
}
void build(int l,int r,int rt){
    if (l == r){
        scanf("%d",&val[rt]);
        a[l] = val[rt];
        return ;
    }
    int m = (l + r)>>1;
    build(lc);
    build(rc);
    pushup(rt);
}
void update(int pos,int l,int r,int rt){
    if (l == r){
        val[rt] = inf;
        return ;
    }
    int m = (l + r)>>1;
    if (pos <= m) update(pos,lc);
    else update(pos,rc);
    pushup(rt);
}
int query(int sc,int l,int r,int rt){
    if (l == r) return l;
    int m = (l + r)>>1;
    if (val[rt<<1|1] < sc) return query(sc,rc);
    else return query(sc,lc);
}
int main(){
    //freopen("data.in","r",stdin);
    int i;
    int n;
    while (~scanf("%d",&n)){
        build(1,n,1);
        for (i = 1; i <= n; ++i){
            update(i,1,n,1);
            if (val[1] >= a[i]){
                printf("-1%c",i == n ? '\n' : ' ');
            }
            else{
                int pos = query(a[i],1,n,1);
                printf("%d%c",pos - i - 1,i == n ?  '\n' : ' ');
            }
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/E-star/archive/2012/10/23/2736202.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值