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;

}

 

你可能感兴趣的:(codeforces)