zoukankan      html  css  js  c++  java
  • POJ 2104 K-th Number

    Time Limit: 20000MS   Memory Limit: 65536K
    Total Submissions: 59481   Accepted: 20727
    Case Time Limit: 2000MS

    Description

    You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment. 
    That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?" 
    For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

    Input

    The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000). 
    The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given. 
    The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).

    Output

    For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

    Sample Input

    7 3
    1 5 2 6 3 7 4
    2 5 3
    4 4 1
    1 7 3

    Sample Output

    5
    6
    3

    Hint

    This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.

    Source

     

    主席树(函数式线段树)裸题

    主席树是一种离线数据结构,是由很多棵线段树组成的。

    第i棵树代表第i个数出现前的情况

    每个线段存数字的出现次数 

    听起来 

    肯定会MLE !

    但是我们发现i和i-1的某些节点完全相同 所以只需要借用以前的点就可以 ,不需要新建。

    那么如果要询问i-j之间数字出现的次数怎么办呢?

    因为每一棵线段树的区间都是相同的,所以要求l-r之间的数字的出现次数只要用前r位出现的次数减去前l-1位出现的次数,就是ans

    但是如果有修改操作怎么办?

    如果沿用上面的做法,那么修改操作是O(nlogn)的,查询是O(1)的,修改要花好长时间。。。

    前缀和联想到了树状数组,那么将前缀和用树状数组维护的话修改是O(logn*logn),查询时O(logn),查询的时间虽然变长,但是修改的时间缩短许多!!

    注意:

    函数式线段树的数组要开大一点!!

    转载自http://blog.csdn.net/regina8023/article/details/41910615

     

    现在还不会主席树,先敲下模板,以后会用到的

    本题没涉及到修改 

    屠龙宝刀点击就送

    #include <algorithm>
    #include <cstdio>
    #define N 105000
    
    using std::sort;
    using std::unique;
    using std::lower_bound;
    
    struct cmt
    {
        int l,r,Size;
    }tr[N*20];
    int a[N],b[N],t[N],tot,Size,n,m,T;
    int build(int l,int r)
    {
        int root=++tot;
        tr[root].Size=0;
        if(l==r) return root;
        int mid=(l+r)>>1;
        tr[root].l=build(l,mid);
        tr[root].r=build(mid+1,r);
        return root;
    }
    int update(int rt,int x)
    {
        int now=++tot;
        int tmp=now;
        tr[now].Size=tr[rt].Size+1;
        for(int mid,l=1,r=Size;l<=r;)
        {
            mid=(l+r)>>1;
            if(x<=mid)
            {
                tr[now].l=++tot;
                tr[now].r=tr[rt].r;
                rt=tr[rt].l;
                now=tot;
                r=mid-1;
            }
            else
            {
                tr[now].l=tr[rt].l;
                tr[now].r=++tot;
                rt=tr[rt].r;
                now=tot;
                l=mid+1;
            }
            tr[now].Size=tr[rt].Size+1;
        }
        return tmp;
    }
    int ask(int lx,int rx,int k)
    {
        int l=1,r=Size;
        for(int mid;l<=r;)
        {
            mid=(l+r)>>1;
            if(tr[tr[rx].l].Size-tr[tr[lx].l].Size>=k)
            {
                rx=tr[rx].l;
                lx=tr[lx].l;
                r=mid-1;
            }
            else
            {
                k-=tr[tr[rx].l].Size-tr[tr[lx].l].Size;
                rx=tr[rx].r;
                lx=tr[lx].r;
                l=mid+1;
            }
        }
        return l;
    }
    int main()
    {
        scanf("%d",&T);
        for(;T--;)
        {
            tot=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i];
            sort(b+1,b+1+n);
            Size=unique(b+1,b+1+n)-b-1;
            t[0]=build(1,Size);
            for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+Size,a[i])-b;
            for(int i=1;i<=n;++i)
            t[i]=update(t[i-1],a[i]);
            for(int x,y,k;m--;)
            {
                scanf("%d%d%d",&x,&y,&k);
                printf("%d
    ",b[ask(t[x-1],t[y],k)]);
            }
        }
        return 0;
    }
    我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。
  • 相关阅读:
    ‘内部系统’怎么测试?两年测试的总结与反思
    微信公众号支付 -- 笔记
    数组处理
    String操作
    number 处理
    date 处理
    type检查
    全选全不选,返回字符串长度,汉字计数为2,获取url中的参数 ,函数防抖,函数节流
    关于移动端兼容BUG问题收集及处理
    nginx 1.6.0 配置文件服务器下载
  • 原文地址:https://www.cnblogs.com/ruojisun/p/7404393.html
Copyright © 2011-2022 走看看