Loading

可持久化线段树

P3834 【模板】可持久化线段树 2(主席树)

这是个非常经典的主席树入门题——静态区间第 \(k\) 小。

对于指定的闭区间 \([l, r]\) 查询其区间内的第 \(k\) 小值.

代码采用指针形式,区间为左闭右闭。

const ll M = 2e5 + 3;
int n, N, m, tot, a[M], b[M];

struct node
{
    int L, R, cnt;
    node *lc, *rc;
};

struct node by[M * 21], *pool = by, *root[M];

node *New()
{
    return ++pool;
}

void update(node *&now)
{
    now->cnt = now->lc->cnt + now->rc->cnt;
}

node *build(int l, int r)
{
    node *now = New();
    now->L = l;
    now->R = r;
    if (l < r)
    {
        int mid = (l + r) >> 1;
        now->lc = build(l, mid);
        now->rc = build(mid + 1, r);
        update(now);
    }
    else
    {
        now->cnt = 0;
        now->lc = now->rc = NULL;
    }
    return now;
}

inline bool out(node *&now, int l, int r)
{
    return (now->R < l) || (r < now->L);
}

void change(node *pre, node *now, int x)
{
    *now = *pre;
    if (pre->L == x and pre->R == x)
        now->cnt++;
    else
    {
        if (!out(pre->lc, x, x))
        {
            now->lc = New();
            change(pre->lc, now->lc, x);
            update(now);
        }
        else
        {
            now->rc = New();
            change(pre->rc, now->rc, x);
            update(now);
        }
    }
}

int check(node *&nowl, node *&nowr, int k)
{
    if (nowl->L == nowl->R)
        return nowl->L;
    int lcnt = nowr->lc->cnt - nowl->lc->cnt;
    if (lcnt >= k)
        return check(nowl->lc, nowr->lc, k);
    else
        return check(nowl->rc, nowr->rc, k - lcnt);
}

void Main()
{
    n = read();
    m = read();
    for (int i = 1; i <= n; ++i)
    {
        a[i] = read();
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    N = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; ++i)
        a[i] = lower_bound(b + 1, b + N + 1, a[i]) - b;
    root[0] = build(1, N);
    for (int i = 1; i <= n; ++i)
    {
        root[++tot] = New();
        change(root[tot - 1], root[tot], a[i]);
    }
    for (int i = 1; i <= m; ++i)
    {
        int l, r, k;
        l = read(), r = read(), k = read();
        int ans = b[check(root[l - 1], root[r], k)];
        printf("%d\n", ans);
    }
}

posted @ 2021-07-19 08:58  EdisonBa  阅读(37)  评论(1编辑  收藏  举报