1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5687 Solved: 2361
[Submit][Status][Discuss]
Description
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Input
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Output
Sample Input
Sample Output
HINT
20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。
升级版的主席树。本道题在普通的主席树上增加了修改这个操作,然而普通的主席树是无法接受的。因此我们想办法去改变主席树,考虑到一个数字序列,维护前缀我们用的是树状数组。以此类比,我们是否可以把一棵棵树当做一个个的数,然后用树状数组去维护,显然这是可行的,因此每改变一棵树,就要操作log次,因此修改的操作就变成了log2n的,对于本题的数据范围可以说轻取,询问操作也同理,一次询问需要log2n的复杂度。因此我们用nlog2n的总复杂K.O.了本题。
代码:
#include<cstdio> #include<algorithm> using namespace std; int n,m,tot,cnt,t1,t2; int a[10010],p[20010],x[10010],y[10010],z[10010],root[10010],L[10010],R[10010]; struct node{int l,r,sum;}tr[5000010]; char s[10]; void change(int l,int r,int &p,int x,int val) { tr[++cnt]=tr[p];p=cnt;tr[p].sum+=val; if (l==r) return; int mid=(l+r)>>1; if (x<=mid) change(l,mid,tr[p].l,x,val);else change(mid+1,r,tr[p].r,x,val); } int ask(int l,int r,int k) { if (l==r) return l; int sum1=0,sum2=0; for (int i=1;i<=t1;i++) sum1+=tr[tr[L[i]].l].sum; for (int i=1;i<=t2;i++) sum2+=tr[tr[R[i]].l].sum; int mid=(l+r)>>1; if (sum2-sum1>=k) { for (int i=1;i<=t1;i++) L[i]=tr[L[i]].l; for (int i=1;i<=t2;i++) R[i]=tr[R[i]].l; return ask(l,mid,k); }else { for (int i=1;i<=t1;i++) L[i]=tr[L[i]].r; for (int i=1;i<=t2;i++) R[i]=tr[R[i]].r; return ask(mid+1,r,k-sum2+sum1); } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); p[++tot]=a[i]; } for (int i=1;i<=m;i++) { scanf("%s",s); if (s[0]=='C'){scanf("%d%d",&x[i],&y[i]);p[++tot]=y[i];}else {scanf("%d%d%d",&x[i],&y[i],&z[i]);} } sort(p+1,p+tot+1); tot=unique(p+1,p+tot+1)-p-1; for (int i=1;i<=n;i++) { a[i]=lower_bound(p+1,p+tot+1,a[i])-p; for (int j=i;j<=n;j+=((j)&(-j))) change(1,tot,root[j],a[i],1); } for (int i=1;i<=m;i++) { if (z[i]) { x[i]--; t1=t2=0; for (int j=x[i];j;j-=((j)&(-j))) L[++t1]=root[j]; for (int j=y[i];j;j-=((j)&(-j))) R[++t2]=root[j]; printf("%d\n",p[ask(1,tot,z[i])]); }else { y[i]=lower_bound(p+1,p+tot+1,y[i])-p; for (int j=x[i];j<=n;j+=((j)&(-j))) change(1,tot,root[j],a[x[i]],-1); for (int j=x[i];j<=n;j+=((j)&(-j))) change(1,tot,root[j],y[i],1); a[x[i]]=y[i]; } } }