BZOJ 1901: Zju2112 Dynamic Rankings
1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 7469 Solved: 3109
[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
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
6
HINT
20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。
Source
分析:
带修改的主席树板子题...
我们之前是把当前根节点的左右儿子连在了上一个根节点的左右儿子,现在因为有修改操作,我们把每一个根节点独立出来成为一棵树,然后当前的节点的左右儿子连在修改之前的线段树的左右儿子...这样我们就无法维护前缀和(每个数字的出现次数),所以这个工作交给了树状数组来完成...
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=20000+5,maxm=10000000+5; int n,m,len,tot,tail,a[maxn],mp[maxn],ls[maxm],rs[maxm],sum[maxm],stk[maxn],sign[maxn],root[maxn]; struct M{ char opt[3]; int s,x,y; }q[maxn]; inline int find( int x){ int l=1,r=len,ans; while (l<=r){ int mid=(l+r)>>1; if (mp[mid]>=x) ans=mid,r=mid-1; else l=mid+1; } return ans; } inline void change( int l, int r, int x, int &y, int val, int w){ y=++tot;sum[y]=sum[x]+w; if (l==r) return ; int mid=(l+r)>>1;ls[y]=ls[x],rs[y]=rs[x]; if (val<=mid) change(l,mid,ls[x],ls[y],val,w); else change(mid+1,r,rs[x],rs[y],val,w); } inline void insert( int x, int num, int v){ for ( int i=x;i<=len;i+=i&-i) change(1,len,root[i],root[i],num,v); } inline void push( int x, int y){ for (;x;x-=x&-x) stk[++tail]=root[x],sign[tail]=y; } inline int query( int l, int r, int num){ if (l==r){ return l; } int res=0; for ( int i=1;i<=tail;i++) res+=sum[ls[stk[i]]]*sign[i]; int mid=(l+r)>>1; if (res>=num){ for ( int i=1;i<=tail;i++) stk[i]=ls[stk[i]]; return query(l,mid,num); } else { for ( int i=1;i<=tail;i++) stk[i]=rs[stk[i]]; return query(mid+1,r,num-res); } } signed main( void ){ scanf ( "%d%d" ,&n,&m);len=n; for ( int i=1;i<=n;i++) scanf ( "%d" ,&a[i]),mp[i]=a[i]; for ( int i=1;i<=m;i++){ scanf ( "%s" ,q[i].opt); if (q[i].opt[0]== 'Q' ) scanf ( "%d%d%d" ,&q[i].x,&q[i].y,&q[i].s); else scanf ( "%d%d" ,&q[i].x,&q[i].y),mp[++len]=q[i].y; } sort(mp+1,mp+len+1);len=unique(mp+1,mp+len+1)-mp-1; for ( int i=1;i<=n;i++) insert(i,find(a[i]),1); for ( int i=1;i<=m;i++){ if (q[i].opt[0]== 'Q' ) tail=0,push(q[i].x-1,-1),push(q[i].y,1), printf ( "%d\n" ,mp[query(1,len,q[i].s)]); else insert(q[i].x,find(a[q[i].x]),-1),a[q[i].x]=q[i].y,insert(q[i].x,find(a[q[i].x]),1); } return 0; } //1234 |
By NeighThorn
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步