P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小

题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组

   但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点

   对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点

   这个方法限制性也很强 必须离线

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 2;

int n, m, len, cnt;
int a[100005];
int b[200005];
int sum[MAXN * 400];
int ls[MAXN * 400];
int rs[MAXN * 400];
int t[MAXN];
int temp[2][50];
int tot1, tot0;

struct node {
    char opt;
    int u, v, w;
}E[100005];

void add(int &o, int l, int r, int k, int v) {
    if(!o) o = ++cnt;
    sum[o] += v;
    int mid = l + r >> 1;
    if(l == r) return;

    if(k <= mid) add(ls[o], l, mid, k, v);
    else add(rs[o], mid + 1, r, k, v);
}

void update(int x, int pos, int v) {
    for(int i = x; i <= n; i += (i & -i)) add(t[i], 1, len, pos, v);
}

void prepare_query(int l, int r) {
    tot1 = tot0 = 0;
    for(int i = r; i >= 1; i -= (i & -i)) temp[1][++tot1] = t[i];
    for(int i = l; i >= 1; i -= (i & -i)) temp[0][++tot0] = t[i];
}

int query(int l, int r, int k) {
    if(l == r) return l;

    int mid = l + r >> 1;
    int res = 0;
    for(int i = 1; i <= tot1; i++) res += sum[ls[temp[1][i]]];
    for(int i = 1; i <= tot0; i++) res -= sum[ls[temp[0][i]]];
    if(res >= k) {
        for(int i = 1; i <= tot1; i++) temp[1][i] = ls[temp[1][i]];
        for(int i = 1; i <= tot0; i++) temp[0][i] = ls[temp[0][i]];
        return query(l, mid, k);
    } else {
        for(int i = 1; i <= tot1; i++) temp[1][i] = rs[temp[1][i]];
        for(int i = 1; i <= tot0; i++) temp[0][i] = rs[temp[0][i]];
        return query(mid + 1, r, k - res);
    }
}

char s[5];
int main() {
    cnt = 0;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
    len = n;
    
    for(int i = 1; i <= m; i++) {
        scanf("%s", s);
        E[i].opt = s[0];
        if(E[i].opt == 'Q') scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
        else {
            scanf("%d%d", &E[i].u, &E[i].v);
            b[++len] = E[i].v;
        }
    }
    sort(b + 1, b + 1 + len);
    len = unique(b + 1, b + 1 + len) - b - 1;

    for(int i = 1; i <= n; i++) {
        int tt = lower_bound(b + 1, b + 1 + len, a[i]) - b;
        update(i, tt, 1);
    }

    for(int i = 1; i <= m; i++) {
        if(E[i].opt == 'Q') {
            prepare_query(E[i].u - 1, E[i].v);
            printf("%d\n", b[query(1, len, E[i].w)]);
        } else {
            int t1 = lower_bound(b + 1, b + 1 + len, a[E[i].u]) - b;
            update(E[i].u, t1, -1);
            a[E[i].u] = E[i].v;
            int t2 = lower_bound(b + 1, b + 1 + len, a[E[i].u]) - b;
            update(E[i].u, t2, 1);
        }
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/lwqq3/p/11315693.html
今日推荐