Dynamic Rankings
Time Limit: 10 Seconds
Memory Limit: 32768 KB
The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.
Your task is to write a program for this computer, which
- Reads N numbers from the input (1 <= N <= 50,000)
- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.
Input
The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.http://www.sn180.com/buyer/buyview/1115832741.html
The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format
Q i j k or
C i t
It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.
There're NO breakline between two continuous test cases.
Output
For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])
There're NO breakline between two continuous test cases.http://www.sn180.com/buyer/buyview/1115821323.html
Sample Input
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
3
6
题意:查找区间第K大值,值可修改
分析:
每一棵线段树是维护每一个序列前缀的值在任意区间的个数,
如果还是按照静态的来做的话,那么每一次修改都要遍历O(n)棵树,
时间就是O(2*M*nlogn)->TLE
考虑到前缀和,我们通过树状数组来优化,即树状数组套主席树,
每个节点都对应一棵主席树,那么修改操作就只要修改logn棵树,
o(nlognlogn+Mlognlogn)时间是可以的,
但是直接建树要nlogn*logn(10^7)会MLE
我们发现对于静态的建树我们只要nlogn个节点就可以了,
而且对于修改操作,只是修改M次,每次改变俩个值(减去原先的,加上现在的)
也就是说如果把所有初值都插入到树状数组里是不值得的,
所以我们分两部分来做,所有初值按照静态来建,内存O(nlogn),
而修改部分保存在树状数组中,每次修改logn棵树,每次插入增加logn个节点
代码:
-
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #include <algorithm>
- #include <stack>
- #include <map>
- #include <set>
- #include <vector>
- #include <queue>
- #define mem(p,k) memset(p,k,sizeof(p));
- #define pb push_back
-
-
- #define inf 0x3f3f3f3f
- #define ll long long
- using namespace std;
- const int N=50010 ;
- struct SD{
- int flag,l,r,k;
- }que[10010];
- int T,n,q,len,tot;
- int num[N],head1[N],head2[N];
- int tree[N*50],lson[N*50],rson[N*50],use[N];
- char s[2];
- vector<int> vec;
-
- int Hash(int k){
-
- return lower_bound(vec.begin(),vec.end(),k)-vec.begin()+1;
- }
- void update(int pre,int &now,int k,int val,int l,int r){
- now=tot++;
- tree[now]=tree[pre]+val;
- lson[now]=lson[pre];rson[now]=rson[pre];
- if(l==r)return;
- int m=(l+r)>>1;
- if(k<=m)update(lson[pre],lson[now],k,val,l,m);
- else update(rson[pre],rson[now],k,val,m+1,r);
- }
- int lowbit(int i){ return -i&i; }
-
- void add(int k,int f,int val){
- for(int i=k;i<=n;i+=lowbit(i)){
- update(head2[i],head2[i],f,val,1,len);
- }
- }
-
- int sum(int k){
- int s=0;
- for(int i=k;i>0;i-=lowbit(i)){
- s+=tree[lson[use[i]]];
- }
- return s;
- }
-
- int Query(int L,int R,int k){
- int s1=head1[L-1],s2=head1[R],l=1,r=len;
- for(int i=L-1;i>0;i-=lowbit(i))use[i]=head2[i];
- for(int i=R;i>0;i-=lowbit(i))use[i]=head2[i];
-
- while(l<r){
- int tmp=sum(R)-sum(L-1)+tree[lson[s2]]-tree[lson[s1]];
- int m=(l+r)>>1;
-
- if(k<=tmp){
- r=m;
- s1=lson[s1];s2=lson[s2];
- for(int i=L-1;i>0;i-=lowbit(i))use[i]=lson[use[i]];
- for(int i=R;i>0;i-=lowbit(i))use[i]=lson[use[i]];
- }
- else{
- k-=tmp;
- l=m+1;
- s1=rson[s1],s2=rson[s2];
- for(int i=L-1;i>0;i-=lowbit(i))use[i]=rson[use[i]];
- for(int i=R;i>0;i-=lowbit(i))use[i]=rson[use[i]];
- }
- }
-
- return vec[l-1];
- }
-
- int main()
- {
- cin>>T;
- while(T--){
- cin>>n>>q;
- tot=1;
- vec.clear();
- mem(tree,0);
- mem(lson,0);
- mem(rson,0);
- for(int i=1;i<=n;i++)scanf("%d",num+i),vec.pb(num[i]);
- for(int i=1;i<=q;i++){
- scanf("%s",s);
- if(s[0]=='Q'){
- que[i].flag=0;
- scanf("%d%d%d",&que[i].l,&que[i].r,&que[i].k);
- }
- else{
- que[i].flag=1;
- scanf("%d%d",&que[i].l,&que[i].k);
- vec.pb(que[i].k);
- }
- }
- sort(vec.begin(),vec.end());
- vec.erase(unique(vec.begin(),vec.end()),vec.end());
- len=vec.size();
-
- head1[0]=0;
- for(int i=1;i<=n;i++){
- update(head1[i-1],head1[i],Hash(num[i]),1,1,len);
- }
-
- for(int i=1;i<=n;i++){
- head2[i]=0;
- }
- for(int i=1;i<=q;i++){
- if(que[i].flag){
- add(que[i].l,Hash(num[que[i].l]),-1);
- add(que[i].l,Hash(que[i].k),1);
- num[que[i].l]=que[i].k;
- }
- else{
- printf("%d\n",Query(que[i].l,que[i].r,que[i].k));
- }
- }
-
- }
-
- return 0;
- }