Dynamic Rankings(动态区间求第K小模板题:树套树(第二份模板效率更高,见下面截图))


Link:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112


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.

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.


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


(adviser)
Site: http://zhuzeyuan.hp.infoseek.co.jp/index.files/our_contest_20040619.htm


Author:  XIN, Tao
Source:  Online Contest of Christopher's Adventure


参考博客:http://blog.youkuaiyun.com/d891320478/article/details/8648171

AC code:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 60010
#define M 60010
#define INF 1000000000
char ctrl[M][3];
int cnt,n,m;
int P[M],Q[M],a[N],b[N],K[M];
struct treap{
   int key,wei,cnt,size,ch[2];
}T[N * 15];
int tree[N << 1],nodecnt,root;
void init(){
   T[0].size = 0;
   T[0].wei = -INF;
   nodecnt = root = 0;
}
int ID(int l,int r){return l + r | l != r;}
void update(int x){
   T[x].size = T[T[x].ch[0]].size + T[T[x].ch[1]].size + T[x].cnt;
}
void rotate(int &x,int t){
   int y = T[x].ch[t];
   T[x].ch[t] = T[y].ch[!t];
   T[y].ch[!t] = x;
   update(x);
   update(y);
   x = y;
}
void insert(int &x,int t){
   if (!x){
       x = ++ nodecnt;
       T[x].key = t;
       T[x].wei = rand();
       T[x].cnt = 1;
       T[x].ch[0] = T[x].ch[1] = 0;
   }else if (T[x].key == t) T[x].cnt ++;
   else{
       int k = T[x].key < t;
       insert(T[x].ch[k],t);
       if (T[x].wei < T[T[x].ch[k]].wei) rotate(x,k);
   }
   update(x);
}
void erase(int &x,int t){
   if (T[x].key == t){
       if (T[x].cnt == 1){
           if (!T[x].ch[0] && !T[x].ch[1]) {
               x = 0;return;
           }
           rotate(x,T[T[x].ch[0]].wei < T[T[x].ch[1]].wei);
           erase(x,t);
       }else T[x].cnt --;
   }else erase(T[x].ch[T[x].key < t],t);
   update(x);
}
int select(int x,int t){
   if (!x) return 0;
   if (T[x].key > t) return select(T[x].ch[0],t);
   return T[x].cnt + T[T[x].ch[0]].size + select(T[x].ch[1],t);
}
void treeins(int l,int r,int i,int x){
   insert(tree[ID(l,r)],x);
   if (l == r) return;
   int m = l + r >> 1;
   if (i <= m) treeins(l,m,i,x);
   else treeins(m + 1,r,i,x);
}
void treedel(int l,int r,int i,int x){
   erase(tree[ID(l,r)],x);
   if (l == r) return;
   int m = l + r >> 1;
   if (i <= m) treedel(l,m,i,x);
   else treedel(m + 1,r,i,x);
}
int query(int l,int r,int x,int y,int t){
   if (l == r) return l;
   int m = l + r >> 1;
   int ans = select(tree[ID(l,m)],y) - select(tree[ID(l,m)],x);
   if (ans >= t) return query(l,m,x,y,t);
   return query(m + 1,r,x,y,t - ans);
}
int main(){
   //freopen("in.txt","r",stdin);
   int Times;
   int cas;
   scanf("%d",&cas);
   while(cas--){
   	   scanf("%d%d",&n,&m);
       memset(tree,0,sizeof tree);
       init();
       cnt = 0;
       for (int i = 1;i <= n;i ++) scanf("%d",&a[i]),b[++ cnt] = a[i];
       for (int i = 1;i <= m;i ++){
           scanf("%s%d%d",ctrl[i],&P[i],&Q[i]);
           if (ctrl[i][0] == 'Q') scanf("%d",&K[i]);
           else b[++ cnt] = Q[i];
       }
       sort(b + 1,b + 1 + cnt);
       cnt = unique(b + 1,b + 1 + cnt) - b - 1;
       for (int i = 1;i <= n;i ++) {
           a[i] = lower_bound(b + 1,b + 1 + cnt,a[i]) - b;
           treeins(1,cnt,a[i],i);
       }
       for (int i = 1;i <= m;i ++){
           if (ctrl[i][0] == 'Q'){
               int id = query(1,cnt,P[i] - 1,Q[i],K[i]);
               printf("%d\n",b[id]);
           }else{
               treedel(1,cnt,a[P[i]],P[i]);
               a[P[i]] = lower_bound(b + 1,b + 1 + cnt,Q[i]) - b;
               treeins(1,cnt,a[P[i]],P[i]);
           }
       }
   }
   return 0;
}

附上别人较简化的代码版本(通过加二分分治优化):

该代码来自博客:http://blog.youkuaiyun.com/firenet1/article/details/47858071

AC code:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
#define maxn 300007
int tree[maxn];
void add(int p,int n){
    for(;p<maxn;p+=p&(-p))
        tree[p]+=n;
}
int query(int p){
    int ans = 0;
    for(;p>0;p-=p&(-p))
        ans += tree[p];
    return ans;
}

struct Node{
    int l,r,k,ty,ans;
};
Node p[maxn];
int id1[maxn],id2[maxn];
void CDQ(int L,int R,int low,int high){
    if(R < L) return ;
    if(low == high ){
        for(;L<=R;L++){
            p[id1[L]].ans = low;
        }
        return ;
    }
    int mid = (low+high)/2,l=L,r=R,k,u;
    for(int i = L;i <= R; i++){
        u = id1[i];
       if(p[u].ty == 2){
            k = query(p[u].r) - query(p[u].l-1);
            if(k >= p[u].k) id2[l++] = u;
            else {
                p[u].k -= k;
                id2[r--] = u;
            }
        }
        else if(p[u].k <= mid){
            add(p[u].l,p[u].ty);
            id2[l++] = u;
        }
        else id2[r--] =  u;
    }

    for(int i = L; i <= R; i++){
        u = id1[i];
        if(p[u].ty != 2 && p[u].k <= mid) add(p[u].l,-p[u].ty);
    }
    for(k=L;k<l;k++)
        id1[k] = id2[k];
    for(r=R;k<=R;k++)
        id1[k] = id2[r--];
    CDQ(L,l-1,low,mid);
    CDQ(l,R,mid+1,high);
}

int num[maxn];

int main(){
    int n,q,t,cnt;
    memset(tree,0,sizeof(tree));
    int cas;
    scanf("%d",&cas);
    while(cas--){
    	scanf("%d%d",&n,&q);
        for(cnt=0;cnt<n;cnt++){
            scanf("%d",&p[cnt].k);
            p[cnt].ty = 1;
            p[cnt].l = cnt+1;
            num[cnt+1] = p[cnt].k;
        }
        //scanf("%d",&q);
        int ty,l,v;
        char ch;
        for(int i = 0;i < q; i++,cnt++){
            scanf("\n%ch",&ch);
            if(ch=='Q')
            {
            	p[cnt].ty=2;
			}
			else
			{
				p[cnt].ty=1;
			}
            if(p[cnt].ty == 1){
                scanf("%d%d",&l,&v);
                p[cnt].ty = -1;
                p[cnt].k = num[l];
                p[cnt].l = l;
                cnt++;
                num[l] = v;
                p[cnt].ty = 1;
                p[cnt].k = v;
                p[cnt].l = l;
            }
            else {
                scanf("%d%d%d",&p[cnt].l,&p[cnt].r,&p[cnt].k);
            }
        }
        for(int i = 0;i < cnt; i++)
            id1[i] = i;
        CDQ(0,cnt-1,0,1000000000);
        for(int i = 0;i < cnt; i++){
            if(p[i].ty == 2) printf("%d\n",p[i].ans);
        }
    }
    return 0;
}


两份代码比较,显然第二份(后提交的那份)更优:

Run IDSubmit TimeJudge StatusPro.IDExe.TimeExe.MemoryCode Len.LanguageAuthor
146888612015-08-29 23:02:59Accepted54121918MS11248K2440 BG++落纸云烟
146884572015-08-29 21:58:02Accepted54124414MS83288K3251 BG++落纸云烟


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值