HDU 3727 Jewel (主席树)


Jewel

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1953    Accepted Submission(s): 501

Problem Description
Jimmy wants to make a special necklace for his girlfriend. He bought many beads with various sizes, and no two beads are with the same size. Jimmy can't remember all the details about the beads, for the necklace is so long. So he turns to you for help. Initially, there is no bead at all, that is, there is an empty chain. Jimmy always sticks the new bead to the right of the chain, to make the chain longer and longer. We number the leftmost bead as Position 1, and the bead to its right as Position 2, and so on. Jimmy usually asks questions about the beads' positions, size ranks and actual sizes. Specifically speaking, there are 4 kinds of operations you should process: Insert x  Put a bead with size x to the right of the chain (0 < x < 231, and x is different from all the sizes of beads currently in the chain) Query_1 s t k  Query the k-th smallest bead between position s and t, inclusive. You can assume 1 <= s <= t <= L, (L is the length of the current chain), and 1 <= k <= min (100, t-s+1) Query_2 x Query the rank of the bead with size x, if we sort all the current beads by ascent order of sizes. The result should between 1 and L (L is the length of the current chain) Query_3 k Query the size of the k-th smallest bead currently (1 <= k <= L, L is the length of the current chain)
 

Input
There are several test cases in the input. The first line for each test case is an integer N, indicating the number of operations. Then N lines follow, each line contains one operation, as described above.  You can assume the amount of "Insert" operation is no more than 100000, and the amounts of "Query_1", "Query_2" and "Query_3" are all less than 35000. There are several test cases in the input. The first line for each test case is an integer N, indicating the number of operations. Then N lines follow, each line contains one operation, as described above.  You can assume the amount of "Insert" operation is no more than 100000, and the amounts of "Query_1", "Query_2" and "Query_3" are all less than 35000.Query the rank of the bead with size x, if we sort all the current beads by ascent order of sizes. The result should between 1 and L (L is the length of the current chain) Query_3 k Query the size of the k-th smallest bead currently (1 <= k <= L, L is the length of the current chain)
 

Output
Output 4 lines for each test case. The first line is "Case T:", where T is the id of the case. The next 3 lines indicate the sum of results for Query_1, Query_2 and Query_3, respectively. 
 

Sample Input
10 Insert 1 Insert 4 Insert 2 Insert 5 Insert 6 Query_1 1 5 5 Query_1 2 3 2 Query_2 4 Query_3 3 Query_3 1
 

Sample Output
Case 1: 10 3 5
Hint
The answers for the 5 queries are 6, 4, 3, 4, 1, respectively.


/*
题意:输入n个需要处理的语句。
		Insert x:插入x 
		Query_1 l,r,k:当前序列[l,r]第k小
		Query_2 x:当前序列X是第几小 
		Query_3 x: 当前序列第X小是啥 
	最后将三种类型的查询结果的和分别输出。
	
思路:Q1和Q3都是区间查询第K小,所以直接套用模板。
	  Q2查询当前区间中比X小的数的个数(在X的左边的都加起来,否则继续向下搜) 
*/

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e6+10;
char a[100];
int b[maxn],c[maxn],root[maxn];
int tot,tot1;
vector<int> v;


struct node1{
    int t;
    int l,r,x;
}q[maxn];

struct node{
    int l,r,sum;
}T[10*maxn];

int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}


void read(int x){
    for(int i=0;i<x;i++){
        cin>>a;
        if(a[0]=='I'){
            q[i].t=0; 
            scanf("%d",&q[i].x);
            v.push_back(q[i].x);
        }else if(a[6]=='1'){
            q[i].t=1;
            scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].x);
        }else if(a[6]=='2'){
            q[i].t=2;
            scanf("%d",&q[i].x);
        }else{
            q[i].t=3;
            scanf("%d",&q[i].x);
        }
    }
}

void update(int l,int r,int &x,int y,int pos){
    T[++tot]=T[y];
    T[tot].sum++;
    x=tot;                        //修改root[i]所指的根节点 
    if(l==r) return ;           //更新完成
    int mid = (l+r)>>1;
    //在左子树 
    if(mid >= pos) update(l,mid,T[x].l,T[y].l,pos);  
    else update(mid+1 ,r ,T[x].r,T[y].r,pos);
}

int query(int l, int r,int x, int y,int val){
    if(l==r) return l;            //查询成功 
    int mid = (l+r)>>1;        
    int sum = T[T[y].l].sum - T[T[x].l].sum;
    if(sum >= val ) return query(l,mid,T[x].l,T[y].l,val);
    else return query(mid+1 ,r ,T[x].r,T[y].r,val-sum);
}

int query2(int l,int r,int x,int y,int val){
    if(l==r) return 1;
    int mid = (l+r)>>1;
    int res=0;
    if(mid >= val){
        res=query2(l,mid,T[x].l,T[y].l,val);
    }else{
        res+=T[T[y].l].sum;
        res+=query2(mid+1,r,T[x].r,T[y].r,val);
    }
    return res;
} 

int main(){
    int n,Case=0;
    while(~scanf("%d",&n)){
        long long ans1=0,ans2=0,ans3=0;
        tot=0;
        v.clear();
        read(n); 
        for(int i=0;i<v.size();i++) b[i+1]=v[i];
        for(int i=0;i<v.size();i++) c[i+1]=v[i];
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        int size=v.size();
        int cnt=1;
        for(int i=0;i<n;i++){
            //更新操作 
            if(q[i].t==0){
                update(1,size,root[cnt],root[cnt-1],getid(q[i].x));
                cnt++;
            }else if(q[i].t==1){
                //区间求第k小
                ans1+=v[query(1,size,root[q[i].l-1],root[q[i].r],q[i].x)-1]; 
            }else if(q[i].t==2){
                //序列X是第几小 
                ans2+=query2(1,size,root[0],root[cnt-1],getid(q[i].x));
            }else{
                //第X小是什么 
                ans3+=v[query(1,size,root[0],root[cnt-1],q[i].x)-1];
            } 
        }
        printf("Case %d:\n",++Case);
        printf("%lld\n%lld\n%lld\n",ans1,ans2,ans3);
    }
} 

展开阅读全文

没有更多推荐了,返回首页