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

Posted lwqq3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

P2617 Dynamic Rankings

P2617 Dynamic Rankings

P2617 Dynamic Rankings(带修主席树)

P2617 Dynamic Rankings(整体二分)

P2617 Dynamic Rankings(动态区间第k小)

「Luogu P2617」Dynamic Rankings