1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 8710 Solved: 3626
[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继续回答上面的问题。
Input
第一行有两个正整数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
m,n≤10000
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
分析:带修改的主席树.
其实主席树就是维护前缀和的权值线段树.单点修改,要O(n)的时间修改前缀和.这样承受不起,需要优化.树状数组就是一个log复杂度维护前缀和的数据结构,那么这道题就可以树状数组套主席树.
主席树每个点表示的是什么要搞清楚.在这道题中,主席树上的每个点代表在树状数组里的点,那么每次修改一个数i都要不停地加lowbit,修改第i棵树.查询同理.
这样的话有一个问题:第i棵线段树不能在以前的树的基础上建立,因为在这里每棵树代表的不再是前缀,而是点.
考虑本题的修改操作,先将原数在树状数组中删除,接着在树状数组中加上新的数.查询操作像树状数组一样,将要查询的根给提出来.注意离散化,要将修改操作的值离散化!
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 20010; int n,m,a[maxn],b[maxn],cnt,tot,ansx[maxn],ansy[maxn],cnt1,cnt2,root[maxn]; struct node { int x,y,z,id; }e[maxn]; struct node2 { int left,right,sum; }tr[2200011]; void update(int l,int r,int &x,int y,int pos,int v) { x = ++tot; tr[x] = tr[y]; tr[x].sum += v; if (l == r) return; int mid = (l + r) >> 1; if (pos <= mid) update(l,mid,tr[x].left,tr[y].left,pos,v); else update(mid + 1,r,tr[x].right,tr[y].right,pos,v); } int query(int l,int r,int p) { if (l == r) return l; int mid = (l + r) >> 1; int res1 = 0,res2 = 0; for (int i = 1; i <= cnt1; i++) res1 += tr[tr[ansx[i]].left].sum; for (int i = 1; i <= cnt2; i++) res2 += tr[tr[ansy[i]].left].sum; if (p <= res2 - res1) { for (int j = 1; j <= cnt1; j++) ansx[j] = tr[ansx[j]].left; for (int j = 1; j <= cnt2; j++) ansy[j] = tr[ansy[j]].left; return query(l,mid,p); } else { for (int j = 1; j <= cnt1; j++) ansx[j] = tr[ansx[j]].right; for (int j = 1; j <= cnt2; j++) ansy[j] = tr[ansy[j]].right; return query(mid + 1,r,p - (res2 - res1)); } } int main() { scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) { scanf("%d",&a[i]); b[i] = a[i]; } cnt = n; for (int i = 1; i <= m; i++) { char ch[2]; scanf("%s",ch); if (ch[0] == 'Q') { scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); e[i].x--; e[i].id = 1; } else { scanf("%d%d",&e[i].x,&e[i].y); e[i].id = 2; b[++cnt] = e[i].y; } } sort(b + 1,b + 1 + cnt); cnt = unique(b + 1,b + 1 + cnt) - b - 1; for (int i = 1; i <= n; i++) { int temp = lower_bound(b + 1,b + 1 + cnt,a[i]) - b; for (int j = i; j <= n; j += j & (-j)) update(1,cnt,root[j],root[j],temp,1); } for (int i = 1; i <= m; i++) { if (e[i].id == 1) { cnt1 = cnt2 = 0; for (int j = e[i].x;j; j -= j & (-j)) ansx[++cnt1] = root[j]; for (int j = e[i].y;j; j -= j & (-j)) ansy[++cnt2] = root[j]; printf("%d ",b[query(1,cnt,e[i].z)]); } else { int temp = lower_bound(b + 1,b + 1 + cnt,a[e[i].x]) - b; for (int j = e[i].x; j <= n; j += j & (-j)) update(1,cnt,root[j],root[j],temp,-1); a[e[i].x] = e[i].y; temp = lower_bound(b + 1,b + 1 + cnt,e[i].y) - b; for (int j = e[i].x; j <= n; j += j & (-j)) update(1,cnt,root[j],root[j],temp,1); } } return 0; }