luogu P2617 Dynamic Rankings && bzoj 1901 (带修改区间第k大)

链接:https://www.luogu.org/problemnew/show/P2617

思路:

如果直接在主席树上修改的话,每次修改都会对后面所有的树造成影响,一次修改的复杂度就会变成 : n*logn,我们套上树状数组维护,每次就最多只用更新logn棵树,复杂度是:logn*logn,是可以接受的;

代码参考hzwer: http://hzwer.com/2835.html

 

实现代码;

#include<bits/stdc++.h>
using namespace std;
const int M = 2e5+10;
int v[M],num[M*2],has[M*2];
int op[M],A[M],B[M],K[M],rt[M];
int sum[M*170],ls[M*170],rs[M*170];
int L[40],R[40],a,b,tot,idx,k;

int lowbit(int x){
    return x&(-x);
}

int find(int x){
    int l = 1,r = tot;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(has[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
    return l;
}

void update(int old,int &k,int p,int c,int l,int r){
    k = ++idx;
    ls[k] = ls[old],rs[k] = rs[old];
    sum[k] = sum[old] + c;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(p <= mid) update(ls[old],ls[k],p,c,l,mid);
    else update(rs[old],rs[k],p,c,mid+1,r);
}

int query(int l,int r,int k){
    if(l == r) return l;
    int suml = 0,sumr = 0;
    for(int i = 1;i <= a;i ++) suml += sum[ls[L[i]]];
    for(int i = 1;i <= b;i ++) sumr += sum[ls[R[i]]];
    int mid = (l + r) >> 1;
    if(sumr - suml >= k){
        for(int i = 1;i <= a;i ++) L[i] = ls[L[i]];
        for(int i = 1;i <= b;i ++) R[i] = ls[R[i]];
        return query(l,mid,k);
    }
    else {
        for(int i = 1;i <= a;i ++) L[i] = rs[L[i]];
        for(int i = 1;i <= b;i ++) R[i] = rs[R[i]];
        return query(mid+1,r,k-(sumr-suml));
    }
}

int main()
{
    int n,m,cnt = 0;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++){
        scanf("%d",&v[i]);
        num[++cnt] = v[i];
    }
    char s[10];
    for(int i = 1;i <= m;i ++){
        scanf("%s",s);
        scanf("%d%d",&A[i],&B[i]);
        if(s[0]=='Q') scanf("%d",&K[i]),op[i] = 1;
        else num[++cnt] = B[i];
    }
    sort(num+1,num+cnt+1);
    has[++tot] = num[1];
    for(int i = 2;i <= cnt;i ++){
        if(num[i] != num[i-1])
            has[++tot] = num[i];
    }
    for(int i = 1;i <= n;i ++){
        int k = find(v[i]);
        for(int j = i;j <= n;j += lowbit(j))
            update(rt[j],rt[j],k,1,1,tot);
    }
    for(int i = 1;i <= m;i ++){
        if(op[i]){
            a = 0; b = 0; A[i]--;
            for(int j = A[i];j > 0;j -= lowbit(j))
                L[++a] = rt[j];
            for(int j = B[i];j > 0;j -= lowbit(j))
                R[++b] = rt[j];
            printf("%d\n",has[query(1,tot,K[i])]);
        }
        else{
            int k = find(v[A[i]]);
            for(int j = A[i];j <= n;j += lowbit(j))
                update(rt[j],rt[j],k,-1,1,tot);
            v[A[i]] = B[i];
            k = find(B[i]);
            for(int j = A[i];j <= n;j += lowbit(j))
                update(rt[j],rt[j],k,1,1,tot);
        }
    }
    return 0;
}

 

posted @ 2019-04-22 19:44  冥想选手  阅读(208)  评论(0编辑  收藏  举报