zoukankan      html  css  js  c++  java
  • POJ2104 K-th Number(主席树)

    题目大意:查询区间k大值

    关于主席树:

    主席树(可持久化线段树,函数式线段树)

    解决区间k大值 用到前缀和思想
    如果前L-1的3个最大值1 2 3 前R个的3个最大值是4 5 6
    那么前三大就是4 5 6
    那如果前R个数前三大是1 5 6呢?那就必须要知道没个数的个数了!因为后面的数2与前面的数做差不就可以了吗?
    但题目是k个数啊 那就维护k个数呗! 线段树!
    建立n+1棵线段树,统计每个数到sz[i]时出现的次数,线段树R比线段树L-1多出来的数中第k大就是答案!但超空间啊
    把所有数排序,去重,线段树中存储的不是数本身而是数的排序 还是空间......
    解决方法:公用节点。

    建立过程:
    1.排序,去重

    sz 2 4 6 8 8 6 4 2
    hash 2 4 6 8
    改成序号 1 2 3 4 4 3 2 1
    2.建立线段树
    先建立空线段树(要用到前缀和)

    然后再根据每一个hash值建立线段树,每加一个数就增加一条链

    实现跟线段树差不多

    //主席树模板 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    const int maxn=100005;
    const int maxnn=10000000;
    int root[maxn],ls[maxnn],rs[maxnn],cnt[maxnn],tot;
    int sz[maxn],hash[maxn];
    
    void build(int &cur,int l,int r)//建立一棵空树 
    {
        cur=tot++;
        cnt[cur]=0;
        if(l!=r)
        {
            int mid=(l+r)/2;
            build(ls[cur],l,mid);
            build(rs[cur],mid+1,r);
        }
    }
    
    void updata(int pre,int ps,int &cur,int l,int r)//往上加线段树 
    {
        cur=tot++;
        cnt[cur]=cnt[pre]+1;
        ls[cur]=ls[pre];rs[cur]=rs[pre];
        if(l==r)return;
        int mid=(l+r)/2;
        if(ps<=mid)updata(ls[pre],ps,ls[cur],l,mid);
        else updata(rs[pre],ps,rs[cur],mid+1,r);
    }
    
    int query(int lt,int rt,int l,int r,int k)//查询k大值 
    {
        if(l==r) return l;
        int mid=(l+r)/2,differ=cnt[ls[rt]]-cnt[ls[lt]];
        if(k<=differ)return query(ls[lt],ls[rt],l,mid,k);
        else return query(rs[lt],rs[rt],mid+1,r,k-differ); 
    }
    
    int main()
    {
        int n,m,l,r,k;
        while(scanf("%d%d",&n,&m)==2)
        {
            for(int i=1;i<=n;i++)
            {
                scanf("%d",sz+i);
                hash[i]=sz[i];
            }
            sort(hash+1,hash+n+1);
            int size=unique(hash+1,hash+n+1)-hash-1;//数组去重 
            for(int i=1;i<=n;i++)
              sz[i]=lower_bound(hash+1,hash+size+1,sz[i])-hash;//得到序号 
            tot=0;
            build(root[0],1,size);
            for(int i=1;i<=n;++i)
                   updata(root[i-1],sz[i],root[i],1,size);
            while(m--)    
            {
                scanf("%d%d%d",&l,&r,&k);
                printf("%d
    ",hash[query(root[l-1],root[r],1,size,k)]);
            }
        }
        return 0;
    }
    心若向阳,无谓悲伤
    //hja 大神的代码 指针版 
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    #define nd(x) (nil + (x))
    
    using namespace std;
    
    const int lim = 1e9; 
    const int N = 100010; 
    const int lg = 60; 
    
    struct node {
        int s; 
        node *lc, *rc; 
    };
    node nil[N * lg], *rot[N]; 
    int cnt; 
    
    int n, m, a[N], dc[N]; 
    
    node* insert(node *u, int l, int r, int p) {
        node *ret = nd(++cnt);
        *ret = *u, ret->s ++;
        if(l == r) return ret;
        
        int mid = (l + r) / 2; 
        if(p <= mid) ret->lc = insert(ret -> lc, l, mid, p); 
        else ret->rc = insert(ret -> rc, mid + 1, r, p); 
        return ret;
    }
    
    int query(node *u, node *v, int l, int r, int k) {
        if(l == r) return dc[l]; 
        int mid = (l + r) / 2; 
        int c = u -> lc -> s - v -> lc -> s; 
        if(k <= c) return query(u -> lc, v -> lc, l, mid, k);
        return query(u -> rc, v -> rc, mid + 1, r, k - c); 
    }
    
    void read() {
        cin >> n >> m; 
        for(int i = 1; i <= n; i++) cin >> a[i]; 
    }
    
    void prep() {
        for(int i=1; i<=n; i++) dc[i] = a[i];
        sort(dc+1, dc+n+1), dc[0] = unique(dc+1, dc+n+1) - dc - 1;
        for(int i=1; i<=n; i++) a[i] = lower_bound(dc+1, dc+dc[0]+1, a[i]) - dc;
    }
    
    void solve() {
        cnt = nil->s = 0, rot[0] = nil->lc = nil->rc = nil;
        for(int i = 1; i <= n; i++) rot[i] = insert(rot[i-1], 1, dc[0], a[i]);
        
        while(m--) {
            int l, r, k;
            cin >> l >> r >> k; 
            cout << query(rot[r], rot[l - 1], 1, dc[0], k) << endl; 
        }
    }
    
    int main() {
        read();
        prep();
        solve(); 
        return 0; 
    }
    世外桃源
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    [cdq分治][树状数组] Bzoj P3262 陌上花开
    [Prufer序列] Bzoj P4766 文艺计算姬
    [欧拉回路][并查集] Bzoj P3706 反色刷
    [欧拉回路][dfs] Uoj #117 欧拉回路
    [并查集][Tarjan] Bzoj P5017 炸弹
    day18
    day17
    树形DP学习笔记
    [分治]JZOJ 6308 中间值
    [贪心][完全背包]JZOJ 6309 完全背包
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6288949.html
Copyright © 2011-2022 走看看