模板 - 有旋Treap
鉴于水平有限,可能会有问题。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls ch[id][0]
#define rs ch[id][1]
const int INF = 1e9;
const int MAXN = 1000000 + 5;
int ch[MAXN][2], dat[MAXN];
int val[MAXN];
int cnt[MAXN];
int siz[MAXN];
ll sum[MAXN];
int tot, root;
inline void Init() {
tot = 0;
root = 0;
}
inline int NewNode(int v, int num) {
int id = ++tot;
ls = rs = 0;
dat[id] = rand();
val[id] = v;
cnt[id] = num;
siz[id] = num;
sum[id] = 1ll * num * v;
return id;
}
inline void PushUp(int id) {
siz[id] = siz[ls] + siz[rs] + cnt[id];
sum[id] = sum[ls] + sum[rs] + 1ll * cnt[id] * val[id];
}
inline void Rotate(int &id, int d) {
int temp = ch[id][d ^ 1];
ch[id][d ^ 1] = ch[temp][d];
ch[temp][d] = id;
id = temp;
PushUp(ch[id][d]);
PushUp(id);
}
//插入num个v
inline void Insert(int &id, int v, int num) {
if(!id)
id = NewNode(v, num);
else {
if(v == val[id])
cnt[id] += num;
else {
int d = val[id] > v ? 0 : 1;
Insert(ch[id][d], v, num);
if(dat[id] < dat[ch[id][d]])
Rotate(id, d ^ 1);
}
PushUp(id);
}
}
//删除至多num个v
void Remove(int &id, int v, int num) {
if(!id)
return;
else {
if(v == val[id]) {
if(cnt[id] > num) {
cnt[id] -= num;
PushUp(id);
} else if(ls || rs) {
if(!rs || dat[ls] > dat[rs])
Rotate(id, 1), Remove(rs, v, num);
else
Rotate(id, 0), Remove(ls, v, num);
PushUp(id);
} else
id = 0;
} else {
val[id] > v ? Remove(ls, v, num) : Remove(rs, v, num);
PushUp(id);
}
}
}
//查询v的排名,排名定义为<v的数的个数+1。
int GetRank(int id, int v) {
int res = 1;
while(id) {
if(val[id] > v)
id = ls;
else if(val[id] == v) {
res += siz[ls];
break;
} else {
res += siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
//查询排名为rk的数,rk必须是正整数,rk过大返回无穷
int GetValue(int id, int rk) {
int res = INF;
while(id) {
if(siz[ls] >= rk)
id = ls;
else if(siz[ls] + cnt[id] >= rk) {
res = val[id];
break;
} else {
rk -= siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
//查询v的前驱的值(<v的第一个节点的值),不存在前驱返回负无穷
int GetPrev(int id, int v) {
int res = -INF;
while(id) {
if(val[id] < v)
res = val[id], id = rs;
else
id = ls;
}
return res;
}
//查询v的后继的值(>v的第一个节点的值),不存在后继返回无穷
int GetNext(int id, int v) {
int res = INF;
while(id) {
if(val[id] > v)
res = val[id], id = ls;
else
id = rs;
}
return res;
}
//查询小于等于v的数的和
ll GetSumValue(int id, int v) {
ll res = 0;
while(id) {
if(val[id] > v)
id = ls;
else if(val[id] == v) {
res += sum[ls] + 1ll * cnt[id] * val[id];
break;
} else {
res += sum[ls] + 1ll * cnt[id] * val[id];
id = rs;
}
}
return res;
}
//查询前rk个数的和,rk必须是正整数
ll GetSumRank(int id, int rk) {
ll res = 0;
while(id) {
if(siz[ls] >= rk)
id = ls;
else if(siz[ls] + cnt[id] >= rk) {
res += sum[ls] + 1ll * (rk - siz[ls]) * val[id];
break;
} else {
res += sum[ls] + 1ll * cnt[id] * val[id];
rk -= siz[ls] + cnt[id];
id = rs;
}
}
return res;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
Init();
int ops;
scanf("%d", &ops);
for(int i = 1; i <= ops; i++) {
int op, x;
scanf("%d%d", &op, &x);
if(op == 1)
Insert(root, x, 1);
else if(op == 2)
Remove(root, x, 1);
else if(op == 3)
printf("%d\n", GetRank(root, x));
else if(op == 4)
printf("%d\n", GetValue(root, x));
else if(op == 5)
printf("%d\n", GetPrev(root, x));
else if(op == 6)
printf("%d\n", GetNext(root, x));
else if(op == 7)
printf("%lld\n", GetSumRank(root, x));
else if(op == 8)
printf("%lld\n", GetSumValue(root, x));
}
return 0;
}