C53 可持久化线段树+离散化 P2464 [SDOI2008] 郁闷的小 J
视频链接:239 可持久化线段树+离散化 P2464 [SDOI2008] 郁闷的小 J_哔哩哔哩_bilibili
#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)); } } }