题意:
给定一个容器,里面存放各种数值,规定三个操作,一个是在容器中增加一个数值,一个是在容器中删掉一个数值,一个是询问容器中比a大的数中第k大的数,将其输出。如果在删除过程中没有这个数,则输出”No Elment!”,如果容器中没有比a大的第k个数,则输出”Not Find!”.
解析:
线段树的单点更新可以解决这题,就是在查找的比a大的第k个元素的时候,要注意先找到a元素的位置,可以用线段树区间询问前缀和,此时的元素的位置就是 sum+k,然后就是套经典的线段树上的第k大问题的解法了。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls o<<1
#define rs o<<1|1
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 100005;
int sumv[N<<2];
inline void pushUp(int o) {
sumv[o] = sumv[ls] + sumv[rs];
}
void build(int o, int L, int R) {
sumv[o] = 0;
if(L == R) return ;
int M = (L + R)/2;
build(lson);
build(rson);
}
void press(int o, int L, int R, int pos) {
if(L == R) {
sumv[o]++;
return ;
}
int M = (L + R)/2;
if(pos <= M) press(lson, pos);
else press(rson, pos);
pushUp(o);
}
void modify(int o, int L, int R, int pos) {
if(L == R) {
if(sumv[o] <= 0) puts("No Elment!");
else sumv[o]--;
return ;
}
int M = (L + R)/2;
if(pos <= M) modify(lson, pos);
else modify(rson, pos);
pushUp(o);
}
int querySum(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr) return sumv[o];
int M = (L + R)/2, ret = 0;
if(ql <= M) ret += querySum(lson, ql, qr);
if(qr > M) ret += querySum(rson, ql, qr);
return ret;
}
int query(int o, int L, int R, int K) {
if(L == R) return L;
int M = (L + R)/2;
if(K <= sumv[ls]) return query(lson, K);
else return query(rson, K - sumv[ls]);
}
int main() {
int m;
while(scanf("%d", &m) != EOF) {
build(1, 1, N);
int op, x, y;
while(m--) {
scanf("%d", &op);
if(op == 0) {
scanf("%d", &x);
press(1, 1, N, x);
}else if(op == 1) {
scanf("%d", &x);
modify(1, 1, N, x);
}else {
scanf("%d%d", &x, &y);
int pos = querySum(1, 1, N, 1, x);
int ret = query(1, 1, N, pos+y);
if(ret >= N) puts("Not Find!");
else printf("%d\n", ret);
}
}
}
return 0;
}