POJ 2104 kth number 主席树(可持久化线段树)[指针实现]

11 篇文章 0 订阅
6 篇文章 0 订阅

大家都很强,可与之共勉。

我不会告诉你们我的输出优化错了,然后调了半天,Woc!
网上几乎都是数组实现的线段树与主席树,我就做一股清(zhuo)流好了。
题目是不带修改的查询区间第k大,注意主席树维护的性质为前缀和,所以是查询[l-1, r]。
然后query( )函数是用非递归形式写的二分查找,免得开栈占空间。其中各种强制&,因为YYF告诉我传参很慢。
代码如下

#include "cctype"
#include "cstdio"
#include "algorithm"

#define atoi(ch) (ch - 48)

template<typename T>
inline bool readIn(T &x)  {
    x = 0;
    T flag = 1;
    char ch;
    while( !isdigit(ch = (char) getchar()) )  if(ch == '-')  flag = -1;
    x = atoi(ch);
    while( isdigit(ch = (char) getchar()) )
        x = (x << 1) + (x << 3) + atoi(ch);
    x *= flag;
}

template<typename T>
inline void write( T x )  {
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + 48);
}

template<typename T>
inline bool writeIn(T x)  {
    if(x < 0)  {
        x = -x;
        putchar('-');
    }
    write(x);
}

const int MAXN = (int) 1e5 + 5;

struct node  {
    int siz;
    node *ls, *rs;
    node() : siz(0), ls(NULL), rs(NULL)  {  }
    inline bool update()  {
        siz = ls -> siz + rs -> siz;
    }
} pool[MAXN * 20], *root[MAXN], *tail = pool, *null;

int n, m, l, r, k, rank[MAXN];

struct id  {
    int idx, x;
    inline bool operator < (const id &rhs) const  {
        return x < rhs.x;
    }
} a[MAXN];

void init()  {
    null = ++tail;
    null -> siz = 0;
    null -> ls = null -> rs = null;
    readIn(n);readIn(m);root[0] = null;
    for(register int i = 1; i <= n; root[i] = null, readIn(a[i].x), a[i].idx = i, ++i);
    std::sort(a + 1, a + 1 + n);
    for(register int i = 1; i <= n; rank[a[i].idx] = i, ++i);
}   

node *insert(node *&pre, int lf, int rg, int &pos)  {
    if(pos < lf || pos > rg)  return pre;
    node *nd = ++tail;
    if(lf == rg)  {
        nd -> siz = pre -> siz + 1;
        return nd;
    }
    int mid = (lf + rg) >> 1;
    nd -> ls = insert(pre -> ls, lf, mid, pos);
    nd -> rs = insert(pre -> rs, mid + 1, rg, pos);
    nd -> update();
    return nd;
}

int query(int lf, int rg, int k)  {
    node *x = root[lf], *y = root[rg];
    int l = 1, r = n;
    while(l != r)  {
        int mid = (l + r) >> 1;
        if( k <= x->ls->siz - y->ls->siz )
             r = mid, x = x -> ls, y = y -> ls;
        else
            k -= (x->ls->siz - y->ls->siz),
            l = mid + 1, x = x -> rs, y = y -> rs;
    }
    return l;
}

int main()  {
    init();
    for(register int i = 1; i <= n; ++i)
        root[i] = insert(root[i-1], 1, n, rank[i]);
    while( m-- )  {
        readIn(l), readIn(r), readIn(k);
        writeIn(a[query(r, l - 1, k)].x);
        putchar('\n');
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值