Description
你需要写一种数据结构,来维护一个集合 A(元素可重复),其中需要支持如下操作:
-
Insert(A,x)
:向集合 A 中插入一个整数 x。 -
Delete(A,x)
:删除集合 A 中值为整数 x 的元素,若有多个相同的数,只删除一个,若 x 不存则忽略。 -
Max(A)
:查询集合中最大的元素,若不存在则忽略。 -
Min(A)
:查询集合中最小的元素,若不存在则忽略。 -
Find(A,x)
:查询整数 x 的元素是否存在,若存在输出Y
,否则输出N
。 -
Pred(A,x)
:查询求 x 的前驱(前驱定义为小于 x,且最大的数),若 x 没有前驱,则忽略。 -
Succ(A,x)
:查询 x 的后继(后继定义为大于 x,且最小的数),若 x 没有后继,则忽略。
最开始,集合中已经有 n 个元素。
Input
第 1 行包含两个整数 n,m,其中 n 表示最初集合 A 中元素的个数, m 表示对集合维护和查询操作数目。
第 2 行包含 n 个整数,表示开始集合 A 中的元素 a[1]..a[n] (∣a[i]∣≤109)。
接下来的 m 行,每行的第一项是操作单词,分别是Insert,Delete,Max,Min,Find,Pred
和Succ
等操作,
若该操作有操作参数,则第二项为一个整数 x,为操作的参数 (0≤∣x∣≤109)。
Output
对应输入中的Max,Min,Find,Pred
和Succ
操作,每个操作输出该操作的执行结果,若要忽略这个操作,则该项没有输出。
Sample Input 1
10 22 8 4 1 6 3 5 9 2 7 6 Insert 10 Delete 5 Min Max Find 6 Pred 6 Succ 8 Delete 6 Delete 1 Insert 0 Delete 10 Insert 8 Delete 3 Find 3 Succ 8 Pred 8 Max Min Delete 4 Delete 9 Succ 8 Pred 8
Sample Output 1
1 10 Y 4 9 N 9 7 9 0 7
Hint
第 1∼6 组数据:0n≤5000,m≤10000。
第 7∼10 组数据:0n≤10000,m≤100000。
第 11∼20 组数据:0n≤200000,m≤2000000。
所有数据都是随机数据。
#include<bits/stdc++.h> #define lc tr[p].ch[0] #define rc tr[p].ch[1] using namespace std; const int maxn = 2500005, inf=0x3f3f3f3f; int read() { int o=0, f=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') f=-1; while(isdigit(ch)) o=o*10+ch-'0', ch=getchar(); return o*f; } struct Treap{ int ch[2]; int val, cnt; int siz, rk; } tr[maxn]; void up(int p) { tr[p].siz = tr[lc].siz + tr[rc].siz + 1; } void rotate(int &p, int d) { int son = tr[p].ch[d]; tr[p].ch[d] = tr[son].ch[d^1]; tr[son].ch[d^1] = p; up(p); up(p=son); } int np=0; void insert(int &p, int x) { if(!p) { tr[p=++np] = (Treap){0, 0, x, 1, 1, rand()}; return; } tr[p].siz++; if(tr[p].val == x) { tr[p].cnt++; return; } int d = tr[p].val < x; insert(tr[p].ch[d], x); if(tr[p].rk > tr[tr[p].ch[d]].rk) rotate(p, d); } void del(int &p, int x) { if(!p) return; if(tr[p].val == x) { if(tr[p].cnt > 1) { tr[p].siz--; tr[p].cnt--; return; } if(!lc || !rc) { p = lc + rc; // 利用引用更新父节点指向 return; } int d = tr[rc].rk < tr[lc].rk; rotate(p, d); del(p, x); } else { int d = tr[p].val < x; del(tr[p].ch[d], x); up(p); } } int find(int p, int x) { while(p && tr[p].val != x) if(tr[p].val < x) p=rc; else p=lc; return p; } int Max(int p) { while(p && rc) p=rc; return p; } int Min(int p) { while(p && lc) p=lc; return p; } int pred(int p, int x) { if(!p) return -inf; if(tr[p].val >= x) return pred(lc, x); return max(tr[p].val, pred(rc, x)); } int suc(int p, int x) { if(!p) return inf; if(tr[p].val <= x) return suc(rc, x); return min(tr[p].val, suc(lc, x)); } void prt(int p) { if(!p) return; prt(lc); printf("%d %d %d %d %d ", p, tr[p].val, tr[p].cnt, lc, rc); prt(rc); } int main() { int n=read(), m=read(), rt=0; while(n--) insert(rt, read()); while(m--) { char op[10]; scanf("%s", op); if(op[0] == 'I') insert(rt, read()); else if(op[0] == 'D') del(rt, read()); else if(op[0] == 'F') puts( find(rt, read())? "Y" : "N"); else if(op[0] == 'P') { int t=pred(rt, read()); if(t != -inf) printf("%d ", t); } else if(op[0] == 'S') { int t=suc(rt, read()); if(t != inf) printf("%d ", t); } else if(op[1] == 'i') { if(rt) printf("%d ", tr[Min(rt)].val); } else { if(rt) printf("%d ", tr[Max(rt)].val); } } return 0; }
-