453 字
2 分钟
COGS 930 [河南省队2012] 找第k小的数

简单题面#

求区间第k小

COGS 1534 == 930 找第k小的数 本来是主席树或树套树的题 然而 可持久化Trie树 可以过

查了查好像用可持久化Trie做区间k小的人很少啊(我好像是没有查到) 事实上 可持久化Trie树 比较好打,代码很短。 本来想用 可持久化Treap 做区间k小的结果和 zzh 又调又改弄了一个晚上 结果发现是真的不能做啊,Treap 区间不可减 他会变化 然后想到了可持久化Trie 发现好像可行啊,然后就出来了。 跑的好像也很快比树套树和不离散的主席树快。

#include <cstdio>
#include <cstring>
using namespace std;
const int full = 21, fix = 1000001;
struct Trie
{
    struct Trie_Node
    {
        Trie_Node *ch[2];
        int s;
        Trie_Node()
        {
            ch[0] = ch[1] = NULL;
            s = 0;
        }
    } * root[100005],*null;
    Trie()
    {
        null = new Trie_Node();
        null->ch[0] = null->ch[1] = null;
        root[0] = new Trie_Node();
        root[0]->ch[1] = root[0]->ch[0] = null;
    }
    Trie_Node *NewNode()
    {
        Trie_Node *rt = new Trie_Node();
        rt->ch[0] = rt->ch[1] = null;
        return rt;
    }
    void copy(Trie_Node *&a, Trie_Node *b)
    {
        if (b == null)
            a = null;
        else
            a = NewNode(), *a = *b;
    }
    void Insert(int x, int cnt)
    {
        x += fix;
        copy(root[cnt], root[cnt - 1]);
        Trie_Node *rt1 = root[cnt], *rt2 = root[cnt - 1];
        for (int i = full; i >= 0; i--)
        {
            int k = (x >> i) & 1;
            copy(rt1->ch[k], rt2->ch[k]);
            if (rt1->ch[k] == null)
                rt1->ch[k] = NewNode();
            rt1 = rt1->ch[k], rt2 = rt2->ch[k];
            rt1->s++;
        }
    }
    int kth(int k, int l, int r)
    {
        int res = 0;
        Trie_Node *rt1 = root[r], *rt2 = root[l - 1];
        for (int i = full; i >= 0; i--)
        {
            if (k > rt1->ch[0]->s - rt2->ch[0]->s)
            {
                k -= (rt1->ch[0]->s - rt2->ch[0]->s);
                res |= (1 << i);
                rt1 = rt1->ch[1], rt2 = rt2->ch[1];
            }
            else
            {
                rt1 = rt1->ch[0], rt2 = rt2->ch[0];
            }
        }
        return res - fix;
    }
} root;
int main()
{
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    int n, m, a;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a);
        root.Insert(a, i);
    }
    int b, k;
    while (m--)
    {
        scanf("%d%d%d", &a, &b, &k);
        printf("%d\n", root.kth(k, a, b));
    }
}
COGS 930 [河南省队2012] 找第k小的数
https://www.nekomio.com/posts/54/
作者
NekoMio
发布于
2017-08-02
许可协议
CC BY-NC-SA 4.0