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

     K-th Number POJ - 2104 

    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.
     
     
    题意:求区间第k大
    题解:主席树的板子
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<sstream>
    #include<cmath>
    #include<stack>
    #include<cstdlib>
    #include <vector>
    #include<queue>
    using namespace std;
    
    #define ll long long
    #define llu unsigned long long
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    const int maxn =  1e5+5;
    const int  mod = 1e9+7;
    
    int n,q,m,tot;
    int a[maxn],t[maxn],T[maxn],lson[maxn*30],rson[maxn*30],c[maxn*30];
    
    void Init_hash()
    {
        for(int i=1;i<=n;i++)
            t[i] = a[i];
         sort(t+1,t+1+n);
         m = unique(t+1,t+1+n)-t-1;
    }
    
    int build(int l,int r)
    {
        int root = tot++;
        c[root] = 0;
        if (l != r)
        {
            int mid = (l+r) >> 1;
            lson[root] = build(l,mid);
            rson[root] = build(mid+1,r);
        }
        return root;
    }
    int Hash(int x)
    {
        return lower_bound(t+1,t+1+m,x)-t;
    }
    int update(int root,int pos,int val)
    {
        int newroot = tot ++,tmp = newroot;
        c[newroot] = c[root] + val;
        int l = 1,r = m;
        while(l <r)
        {
            int mid = (l+r)>>1;
            if(pos <= mid)
            {
                lson[newroot] = tot++;
                rson[newroot] = rson[root];
                newroot = lson[newroot];
                root = lson[root];
                r = mid;
            }
            else
            {
                rson[newroot] = tot ++;
                lson[newroot] = lson[root];
                newroot = rson[newroot];
                root = rson[root];
                l = mid + 1;
            }
            c[newroot] = c[root] + val;
        }
        return tmp;
    
    }
    int query(int left_root,int right_root,int k)
    {
        int l = 1,r = m;
        while(l < r)
        {
            int mid = (l+r) >> 1;
            if(c[lson[left_root]] - c[lson[right_root]] >= k)
            {
                r = mid;
                left_root = lson[left_root];
                right_root = lson[right_root];
            }
            else
            {
                l = mid + 1;
                k -= c[lson[left_root]] - c[lson[right_root]];
                left_root = rson[left_root];
                right_root = rson[right_root];
            }
        }
        return l;
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        tot = 0;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        Init_hash();
        T[n+1] = build(1,m);
        for(int i=n;i;i--)
        {
            int pos = Hash(a[i]);
            T[i] = update(T[i+1],pos,1);
        }
        while(q--)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
    ",t[query(T[l],T[r+1],k)]);
        }
    }
    View Code
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<stack>
    #include<cstdlib>
    #include<queue>
    #include<set>
    #include<string.h>
    #include<vector>
    #include<deque>
    #include<map>
    using namespace std;
    #define INF 0x3f3f3f3f3f3f3f3f
    #define inf 0x3f3f3f3f
    #define eps 1e-4
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    typedef long long LL;
    typedef long long ll;
    const int maxn = 2e5 + 5;
    const int mod = 998244353;
    int n,m,a[maxn],root[maxn],cnt;
    vector<int>v;
    struct node{
        int l,r,sum;
    }T[maxn * 40];
    int getid(int x) {
        return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
    }
    void update(int l,int r,int &x,int y,int pos) {
        T[++cnt] = T[y],T[cnt].sum ++,x = cnt;
        if(l == r) return;
        int mid = (l + r) / 2;
        if(mid >= pos) update(l,mid,T[x].l,T[y].l,pos);
        else update(mid + 1,r,T[x].r,T[y].r,pos);
    }
    int query(int l,int r,int x,int y,int k) {
        if(l == r) return l;
        int mid = (l + r) / 2;
        int sum = T[T[y].l].sum - T[T[x].l].sum;
        if(sum >= k) return query(l,mid,T[x].l,T[y].l,k);
        else return query(mid + 1,r,T[x].r,T[y].r,k - sum);
    }
    void init() {
        cnt = 0;
        memset(root,0,sizeof root);
    }
    int main()
    {
        init();
        scanf("%d %d",&n,&m);
        for (int i = 1; i <= n; ++i) {
            scanf("%d",&a[i]);
            v.push_back(a[i]);
        }
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        for (int i = 1; i <= n; ++i)
            update(1,n,root[i],root[i - 1],getid(a[i]));
        for (int i = 1; i <= m; ++i) {
            int x,y,k;
            scanf("%d %d %d",&x, &y, &k);
            printf("%d
    ",v[query(1,n,root[x - 1],root[y],k) - 1]);
        }
    }
    View Code
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<stack>
    #include<cstdlib>
    #include<queue>
    #include<set>
    #include<string.h>
    #include<vector>
    #include<deque>
    #include<map>
    using namespace std;
    #define INF 0x3f3f3f3f3f3f3f3f
    #define inf 0x3f3f3f3f
    #define eps 1e-4
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    typedef long long LL;
    typedef long long ll;
    const int maxn = 2e5 + 5;
    const int mod = 998244353;
    int n,m,a[maxn],root[maxn],cnt;
    /*
     root:代表每个历史版本线段树的根节点位置
     cnt:用作开辟新的树节点
     */
    vector<int>v;
    struct node{
        int l,r,sum;
    }T[maxn * 40];  //线段树区间统计,sum代表在这个区间数的个数
    int getid(int x) {      //获取离散数组后的下标
        return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
    }
    /*
     update函数:
     y代表前一棵树的节点位置,x是后面的节点位置
     */
    void update(int l,int r,int &x,int y,int pos) {
        //&x 引用节点指针扩展新节点
        T[++cnt] = T[y],T[cnt].sum ++,x = cnt;  //新开节点,将需要修改的树节点复制到新开辟节点,改变自己的sum
        if(l == r) return;
        int mid = (l + r) / 2;
        if(mid >= pos) update(l,mid,T[x].l,T[y].l,pos); //节点左边
        else update(mid + 1,r,T[x].r,T[y].r,pos);      //节点右边
    }
    int query(int l,int r,int x,int y,int k) {
        if(l == r) return l;
        int mid = (l + r) / 2;
        int sum = T[T[y].l].sum - T[T[x].l].sum;    //两颗线段树sum做差
        if(sum >= k) return query(l,mid,T[x].l,T[y].l,k);   //如果当前的结点个数sum比k要大的话,说明第k大的结点在左子树当中,就去遍历左子树
        else return query(mid + 1,r,T[x].r,T[y].r,k - sum); //如果当前的结点个数sum比k要小的话,说明第k大的结点在右子树当中,而左子树的结点个数是sum个,那就去找右子树中的第k-sum的数
    }
    void init() {
        cnt = 0;
        memset(root,0,sizeof root);
    }
    int main()
    {
        init();
        scanf("%d %d",&n,&m);
        for (int i = 1; i <= n; ++i) {
            scanf("%d",&a[i]);
            v.push_back(a[i]);      //离散化数组
        }
        sort(v.begin(),v.end());    //离散化数组
        v.erase(unique(v.begin(),v.end()),v.end()); //离散化数组
    
        for (int i = 1; i <= n; ++i) {
            update(1, n, root[i], root[i - 1], getid(a[i]));
        }
        for (int i = 1; i <= m; ++i) {
            int x,y,k;
            scanf("%d %d %d",&x, &y, &k);
            printf("%d
    ",v[query(1,n,root[x - 1],root[y],k) - 1]);
        }
    }
    View Code
  • 相关阅读:
    FrameLayout和handle实现霓虹灯效果
    Table中collapseColumns,stretchColumns
    自定义View,随着手指运动的小球
    用代码创建视图
    Android scrollbar的设置
    Android安装和设置的方法
    将win7电脑无线网变身WiFi热点,让手机、笔记本共享上网
    同一个ImageView根据xml文件来显示不同的图片--level-list
    android获取屏幕长宽的方法
    Android实现图片裁剪
  • 原文地址:https://www.cnblogs.com/smallhester/p/10300566.html
Copyright © 2011-2022 走看看