点更新主席树

本文介绍了一种解决区间更新与查询问题的有效方法,通过离线处理和使用线段树及树状数组相结合的技术实现。文章详细展示了如何利用这些数据结构进行区间修改和查询操作,适用于诸如ZOJ 2112等算法竞赛题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

///zoj 2112
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define mid (l+r)/2
#define w(i) T[(i)].w
#define ls(i) T[(i)].ls
#define rs(i) T[(i)].rs

const int N=60010;
const int M=N*40;
struct Tree{
    int ls,rs,w;
}T[M];
int rt[N],tot,ht[N];
int Pos,Val;
void update(int &o,int l,int r){
    T[++tot]=T[o];o=tot;
    T[o].w+=Val;
    if(l==r) return;
    if(Pos<=mid)update(T[o].ls,l,mid);
    else update(T[o].rs,mid+1,r);
}

int n,m;
int lowbit(int x){return x&(-x);}
void add(int pos,int x,int val){
    Pos=x,Val=val;
    for(;pos<=n;pos+=lowbit(pos))update(rt[pos],1,m);
}
int use[2][N];
int sum(int x,int p){
    int ret=0;
    for(;x;x-=lowbit(x))ret+=T[T[use[p][x]].ls].w;
    return ret;
}
int L,R;
int lo,ro;
int query(int l,int r,int k,int p){
    if(l==r) return l;
    int tmp=sum(R,p)-sum(L-1,p);
    tmp+=T[T[ro].ls].w-T[T[lo].ls].w;
    if(k<=tmp){
        for(int i=L-1;i;i-=lowbit(i))use[p^1][i]=T[use[p][i]].ls;
        for(int i=R;i;i-=lowbit(i))use[p^1][i]=T[use[p][i]].ls;
        lo=T[lo].ls,ro=T[ro].ls;
        return query(l,mid,k,p^1);
    }
    else{
        for(int i=L-1;i;i-=lowbit(i))use[p^1][i]=T[use[p][i]].rs;
        for(int i=R;i;i-=lowbit(i))use[p^1][i]=T[use[p][i]].rs;
        lo=T[lo].rs,ro=T[ro].rs;
        return query(mid+1,r,k-tmp,p^1);
    }
}

struct Node{
    int l,r,k;
}node[10002];
int a[N],b[N],q;
void init(){
    sort(b,b+m);
    m=unique(b,b+m)-b;
}
int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    #endif // DouBi
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);
        tot=m=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]); b[m++]=a[i];
        }
        for(int i=1;i<=q;i++){
            char op[2]; scanf("%s",op);
            if(op[0]=='Q'){
                scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].k);
            }
            else{
                scanf("%d%d",&node[i].l,&node[i].r);
                node[i].k=0; b[m++]=node[i].r;
            }
        }
        init();
        memset(T,0,sizeof(T[0]));rt[0]=0;ht[0]=0;
        for(int i=1;i<=n;i++)rt[i]=rt[0];
        for(int i=1;i<=n;i++){
            int pos=lower_bound(b,b+m,a[i])-b+1;ht[i]=ht[i-1];
            Pos=pos,Val=1;
            update(ht[i],1,m);
        }
        for(int i=1;i<=q;i++){
            if(node[i].k){
                L=node[i].l,R=node[i].r;
                lo=ht[node[i].l-1],ro=ht[node[i].r];
                for(int j=L-1;j;j-=lowbit(j))use[0][j]=rt[j];
                for(int j=R;j;j-=lowbit(j))use[0][j]=rt[j];
                printf("%d\n",b[query(1,m,node[i].k,0)-1]);
            }
            else{
                int id=node[i].l, val=node[i].r;
                int pos=lower_bound(b,b+m,a[id])-b+1;
                add(id,pos,-1);
                pos=lower_bound(b,b+m,val)-b+1;
                add(id,pos,1);
                a[id]=val;
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值