• 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;
    }
    我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。
  • 相关阅读:
    PAT甲级1091Acute Stroke
    PAT甲级1076Forwards on Weibo
    PAT甲级1131Subway Map
    PAT甲级1130Infix Expression
    PAT甲级1103Integer Factorization
    PAT甲级1034Head of a Gang
    Blender删除历史材质球未用材质球
    王者荣耀 花木兰 水晶猎龙者 同人3D壁纸 木兰小哥哥也有拧不开瓶盖的时候,嘿嘿嘿 家居服 减布料
    王者荣耀 嫦娥 同人 3D渲染 壁纸 家居服 减布料
    联考6
  • 原文地址:https://www.cnblogs.com/ruojisun/p/7404393.html
Copyright © 2020-2023  润新知