C53 可持久化线段树+离散化 P2464 [SDOI2008] 郁闷的小 J

视频链接:239 可持久化线段树+离散化 P2464 [SDOI2008] 郁闷的小 J_哔哩哔哩_bilibili

 

 

 

 

Luogu P2464 [SDOI2008] 郁闷的小 J

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

const int N=100005;
#define mid ((l+r)>>1)
int n,m,a[N],b[N*2]; //b:用于离散化
struct node{
  int opt,l,r,id;    //id:书的编码
}q[N];               //保存操作
int root[N],tot,cnt;
int ls[N*25],rs[N*25],sum[N*25];    
//tot:开点个数 cnt:书的编码的个数
//sum:区间数的个数

void pushup(int u){ //上传
  sum[u]=sum[ls[u]]+sum[rs[u]];  
}
void change(int &u,int l,int r,int p,int k){ //点修
  if(!u) u=++tot;
  if(l==r){sum[u]+=k; return;}
  if(p<=mid) change(ls[u],l,mid,p,k);
  else change(rs[u],mid+1,r,p,k);
  pushup(u);
}
int query(int u,int l,int r,int x,int y){ //区查
  if(x<=l&&r<=y) return sum[u];
  int s=0;
  if(x<=mid) s+=query(ls[u],l,mid,x,y);
  if(y>mid) s+=query(rs[u],mid+1,r,x,y);
  return s;
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++)
    scanf("%d",&a[i]),b[++cnt]=a[i]; //保存书的编号
  for(int i=1;i<=m;i++){ //保存操作
    char s[2]; scanf("%s",s);
    if(s[0]=='C')q[i].opt=0,scanf("%d%d",&q[i].l,&q[i].id);
    else q[i].opt=1,scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].id);
    b[++cnt]=q[i].id; //保存书的编号
  }
  sort(b+1,b+cnt+1);
  int bn=unique(b+1,b+cnt+1)-b-1; //去重
  for(int i=1;i<=n;i++){
    a[i]=lower_bound(b+1,b+bn+1,a[i])-b; //编码变成离散值
    change(root[a[i]],1,n,i,1); //按离散值建可持久化线段树
  }
  for(int i=1;i<=m;i++){ //处理操作
    if(!q[i].opt){ //更换图书
      change(root[a[q[i].l]],1,n,q[i].l,-1);
      a[q[i].l]=lower_bound(b+1,b+bn+1,q[i].id)-b;
      change(root[a[q[i].l]],1,n,q[i].l,1);
    }
    else{ //查询某编码的书的个数
      int id=lower_bound(b+1,b+bn+1,q[i].id)-b;
      printf("%d\n",query(root[id],1,n,q[i].l,q[i].r));
    }
  }
}

 

posted @ 2023-10-26 21:12  董晓  阅读(170)  评论(0编辑  收藏  举报