= Vain学习(C/C++ acm算法 python Linux Golang)的个人网站 =

线段树实现普通平衡树操作

Posted on

洛谷: 3369 (模板)普通平衡树

题目描述:

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  • 1.插入 xx 数
  • 2.删除 xx 数(若有多个相同的数,因只删除一个)
  • 3.查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 )
  • 4.查询排名为 xx 的数
  • 5.求 xx 的前驱(前驱定义为小于 xx,且最大的数)
  • 6.求 xx 的后继(后继定义为大于 xx,且最小的数)

输入格式

第一行为 n,表示操作的个数,下面 n 行每行有两个数 opt 和 x,opt 表示操作的序号( 1<=opt<=6)

输出格式

对于操作 3,4,5,6 每行输出一个数,表示对应答案

输入输出样例

输入 #1

1
2
3
4
5
6
7
8
9
10
11
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

输出 #1

1
2
3
106465
84185
492737

数据范围

对于100%的数据,1<=n<=100000,|x|<=10000000

思路:

用权值线段树,求整体区间的第k小,从而来实现1,2,4操作,然后利用前缀和的思路来求x的排名,从而实现3,5,6操作
具体操作,参考以下代码

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <set>
using namespace std;
const int inf = (1 << 30);
typedef long long ll;
const int maxn = 1e5 + 5;
struct node
{
int ls, rs, sum, lv, rv;
} tr[maxn * 50];
int cnt;
void pushup(int k)
{
tr[k].sum = tr[tr[k].ls].sum + tr[tr[k].rs].sum;
}
void inser(int &k, int L, int R, int pos, int w)
{
if (!k)
k = ++cnt;
if (L == R)
{
tr[k].sum += w;
return;
}
int mid = L + R >> 1;
if (mid >= pos)
inser(tr[k].ls, L, mid, pos, w);
else
inser(tr[k].rs, mid + 1, R, pos, w);
pushup(k);
}
int asik(int k, int L, int R, int ik)
{
if (L == R)
return L;
int mid = L + R >> 1;
if (tr[tr[k].ls].sum >= ik)
return asik(tr[k].ls, L, mid, ik);
else
return asik(tr[k].rs, mid + 1, R, ik - tr[tr[k].ls].sum);
}
int ask(int k, int L, int R, int ql, int qr)
{
if (L >= ql && R <= qr)
{
return tr[k].sum;
}
int mid = L + R >> 1;
int ans = 0;
if (ql <= mid)
ans += ask(tr[k].ls, L, mid, ql, qr);
if (qr > mid)
ans += ask(tr[k].rs, mid + 1, R, ql, qr);
return ans;
}
map<int,int>mp;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, k = 0;
cin >> n;
while (n--)
{
int op, x;
cin >> op >> x;
if (op == 1)
inser(k, -inf, inf, x, 1),mp[x]++;
if (op == 2)
inser(k, -inf, inf, x, -1),mp[x]--;
if (op == 3)
{

inser(k, -inf, inf, x, 1),mp[x]++;
int l = asik(k, -inf, inf, 1);
cout << ask(k, -inf, inf, l, x)-mp[x]+1<< endl;
inser(k,-inf,inf,x,-1),mp[x]--;
}
if (op == 4)
{
cout << asik(k, -inf, inf, x) << endl;
}
if (op == 5)
{
inser(k, -inf, inf, x, 1),mp[x]++;
int l = asik(k, -inf, inf, 1);
int ans = ask(k, -inf, inf, l, x);
cout << asik(k, -inf, inf, ans - mp[x]) << endl;
inser(k, -inf, inf, x, -1),mp[x]--;
}
if (op == 6)
{
inser(k, -inf, inf, x, 1);
int l = asik(k, -inf, inf, 1);
int ans = ask(k, -inf, inf, l, x);
cout << asik(k, -inf, inf, ans+1) << endl;
inser(k, -inf, inf, x, -1);
}
}
}