题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3727
题意是有4种操作
1、在项链后面插入一个珍珠,保证每一个珍珠都不一样
2、查询第 l 到 第 r 个珍珠之间第k大的珍珠的大小
3、假设把所有珍珠按照大小排序,查询size为x的珍珠的排名
4、查询所有珍珠里第k大的珍珠的大小
题目只需要输出2,3,4询问的所有答案即可
第3个询问很简单,不谈。第4个询问本质上和上一道CWOJ的题是一样的。而第2个操作需要用到主席树的思想。
建立n棵线段树T(i),T(i).sum记录[1, i]区间内有多少个数,线段树上是以数的数值从小到大来建立的,比如T(i)(x)表示的就是[1, i]区间内大小为 i 的数有多少个(这里的大小指的是离散化之后的)
用主席树的方法来建立这n棵线段树
查询操作用主席树的方法来查询即可
//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
#define N 100010
#define M 35010
int n;
char s[100];
//存储询问
struct Query{
int ty, x;
int l, r, k;
}q[N + 3 * M];
#define MAXN (N + M) * (4 + 17)
int lch[MAXN], rch[MAXN], val[MAXN], T[N], nnod, tem[N + M], ntem;
//建立一棵空线段树
int plant(int l, int r){
int t = ++nnod;
val[t] = 0;
if(l == r) return t;
int mid = (l + r) >> 1;
lch[t] = plant(l, mid);
rch[t] = plant(mid + 1, r);
return t;
}
//建立每棵线段树
int update(int id, int p, int l, int r, int v){
int t = ++nnod;
lch[t] = lch[id], rch[t] = rch[id], val[t] = val[id] + v;
if(l == r) return t;
int mid = (l + r) >> 1;
if(p <= mid) lch[t] = update(lch[t], p, l, mid, v);
else rch[t] = update(rch[t], p, mid + 1, r, v);
return t;
}
//
int query(int lid, int rid, int l, int r, int k){
if(l == r) return l;
int mid = (l + r) >> 1;
int lsum = val[lch[rid]] - val[lch[lid]];//容易出错
if(lsum >= k) return query(lch[lid], lch[rid], l, mid, k);
else return query(rch[lid], rch[rid], mid + 1, r, k - lsum);
}
//
int query2(int id, int ql, int qr, int l, int r){
if(ql == l && qr == r) return val[id];
int mid = (l + r) >> 1;
if(qr <= mid) return query2(lch[id], ql, qr, l, mid);
else if(mid < ql) return query2(rch[id], ql, qr, mid + 1, r);
else return query2(lch[id], ql, mid, l, mid) + query2(rch[id], mid + 1, qr, mid + 1, r);
}
int main(){
ll ans1, ans2, ans3;
int kase = 1;
while(~scanf("%d",&n)){
ntem = 0;
for(int i = 1; i <= n; i++){
scanf("%s",s);
if(s[0] == 'I'){
q[i].ty = 0;
scanf("%d", &q[i].x);
tem[++ntem] = q[i].x;
}
else if(s[6] == '1'){
q[i].ty = 1;
scanf("%d%d%d",&q[i].l, &q[i].r, &q[i].k);
}
else if(s[6] == '2'){
q[i].ty = 2;
scanf("%d",&q[i].x);
tem[++ntem] = q[i].x;
}
else if(s[6] == '3'){
q[i].ty = 3;
scanf("%d",&q[i].k);
}
}
//离散化
sort(tem + 1, tem + 1 + ntem);
ntem = (int)(unique(tem + 1, tem + 1 + ntem) - (tem + 1));
for(int i = 1; i <= n; i++){
if(q[i].ty == 0 || q[i].ty == 2){
q[i].x = (int)(lower_bound(tem + 1, tem + 1 + ntem, q[i].x) - tem);
}
}
nnod = 0;
T[0] = plant(1, ntem);
int nowp = 0;
ans1 = ans2 = ans3 = 0;
for(int i = 1; i <= n; i++){
if(q[i].ty == 0){
++nowp;
T[nowp] = update(T[nowp - 1], q[i].x, 1, ntem, +1);
}
else if(q[i].ty == 1){
int t = query(T[q[i].l - 1], T[q[i].r], 1, ntem, q[i].k);
ans1 += tem[t];
}
else if(q[i].ty == 2){
ans2 += query2(T[nowp], 1, q[i].x, 1, ntem);
}
else if(q[i].ty == 3){
int t = query(T[0], T[nowp], 1, ntem, q[i].k);
ans3 += tem[t];
}
}
printf("Case %d:\n",kase++);
//记得hdu上用%I64d
printf("%I64d\n%I64d\n%I64d\n",ans1,ans2,ans3);
//printf("%lld\n%lld\n%lld\n",ans1,ans2,ans3);
}
return 0;
}