【传送门:BZOJ1901】
简要题意:
给出一个长度为n的序列,有两种操作,m个操作:
Q l r k求出l到r第k小的值
C x c将第x个数变成c
题解:
带修主席树例题,用树状数组来维护修改
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; int a[11000]; struct node { int lc,rc,c; }tr[3100000];int cnt; int rt[110000];int n; int ust[110000]; int lowbit(int x){return x&-x;} void link(int &u,int l,int r,int p,int c) { if(u==0) u=++cnt; tr[u].c+=c; if(l==r) return ; int mid=(l+r)/2; if(p<=mid) link(tr[u].lc,l,mid,p,c); else link(tr[u].rc,mid+1,r,p,c); } void merge(int &u1,int u2) { if(u1==0){u1=u2;return ;} if(u2==0) return ; tr[u1].c+=tr[u2].c; merge(tr[u1].lc,tr[u2].lc); merge(tr[u1].rc,tr[u2].rc); } void Turn(int u,int c) { while(u>=n+1) { if(c==-1) ust[u]=rt[u]; else if(c==0) ust[u]=tr[ust[u]].lc; else if(c==1) ust[u]=tr[ust[u]].rc; u-=lowbit(u); } } void change(int u,int p,int c) { while(u<=2*n) { link(rt[u],0,1000000000,p,c); u+=lowbit(u); } } int getsum(int u) { int ret=0; while(u>=n+1) { ret+=tr[tr[ust[u]].lc].c; u-=lowbit(u); } return ret; } int findkth(int u1,int u2,int p1,int p2,int l,int r,int p) { if(l==r) return l; int c=tr[tr[u2].lc].c-tr[tr[u1].lc].c+getsum(p2+n)-getsum(p1+n); int mid=(l+r)/2; if(p<=c) { Turn(p1+n,0); Turn(p2+n,0); return findkth(tr[u1].lc,tr[u2].lc,p1,p2,l,mid,p); } else { Turn(p1+n,1); Turn(p2+n,1); return findkth(tr[u1].rc,tr[u2].rc,p1,p2,mid+1,r,p-c); } } int main() { int m; scanf("%d%d",&n,&m); cnt=0;memset(rt,0,sizeof(rt)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); link(rt[i],0,1000000000,a[i],1); merge(rt[i],rt[i-1]); } char st[2]; for(int i=1;i<=m;i++) { scanf("%s",st+1); if(st[1]=='Q') { int l,r,k; scanf("%d%d%d",&l,&r,&k); Turn(l+n-1,-1); Turn(r+n,-1); printf("%d ",findkth(rt[l-1],rt[r],l-1,r,0,1000000000,k)); } else { int p,c; scanf("%d%d",&p,&c); change(p+n,a[p],-1); a[p]=c; change(p+n,a[p],1); } } return 0; }