zoukankan      html  css  js  c++  java
  • poj2828(线段树查找序列第k小的值)

    题目链接:https://vjudge.net/problem/POJ-2828

    题意:有n个人,依次给出这n个人进入队列时前面有多少人p[i],和它的权值v[i],求最终队列的权值序列。

    思路:基本类似于poj2182,简化题意后即为求序列1..n中第k小的值的问题。读入数据量比较大,最好读入优化。我们从n..1逆序遍历,则可以确认最后一个人的最终位置为p[n]+1,然后从序列中删除p[n]+1,继续操作倒数第二个...这一操作可以通过线段树来完成。线段树的结点包括3个值:l(区间左端点),r(区间右端点),len(区间剩余编号数)。每次询问维护len值。时间复杂度为O(Tnlogn)。

    AC代码:

    #include<cstdio>
    #include<cctype>
    using namespace std;
    const int maxn=200005;
    
    inline int read(){
        int x=0,f=0;char c=0;
        while(!isdigit(c)) {f|=c=='-';c=getchar();}
        while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return f?-x:x;
    }
    
    struct node{
        int l,r,len;
    }tr[4*maxn];
    
    int p[maxn],v[maxn],n,ans[maxn];
    
    void build(int v,int l,int r){
        tr[v].l=l,tr[v].r=r,tr[v].len=r-l+1;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(2*v,l,mid);
        build(2*v+1,mid+1,r);
    }
    
    int query(int v,int k){
        --tr[v].len;
        if(tr[v].l==tr[v].r) return tr[v].l;
        if(k<=tr[2*v].len) return query(2*v,k);
        else return query(2*v+1,k-tr[2*v].len);
    }
    
    int main(){
        while(~scanf("%d",&n)){
            build(1,1,n);
            for(int i=1;i<=n;++i)
                p[i]=read(),v[i]=read();
            for(int i=n;i>=1;--i)
                ans[query(1,p[i]+1)]=v[i];
            for(int i=1;i<=n;++i)
                printf("%d ",ans[i]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    勒布朗法则( LeBlanc)
    [转]五分钟看懂UML类图与类的关系详解
    单片机裸机下写一个自己的shell调试器(转)
    S3C2440 偷学
    LWIP_STM32_ENC28J60(转)
    写出稳定的Modbus代码之点滴经验
    GPS数据解析
    U-BLOX GPS 模块及GPRMC指令解析
    LwIP之socket应用--WebServer和Modbus TCP
    LWIP使用经验---变态级(转)
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10778996.html
Copyright © 2011-2022 走看看