P6136 【模板】普通平衡樹(資料加強版)
阿新 • • 發佈:2021-08-17
【模板】普通平衡樹(資料加強版)
題目背景
本題是 P3369 資料加強版,**擴大資料範圍**並增加了**強制線上**。 **題目的輸入、輸出和原題略有不同**,但需要支援的操作相同。題目描述
您需要寫一種資料結構(可參考題目標題),來維護一些整數,其中需要提供以下操作:- 插入一個整數 \(x\)。
- 刪除一個整數 \(x\)(若有多個相同的數,只刪除一個)。
- 查詢整數 \(x\) 的排名(排名定義為比當前數小的數的個數 \(+1\))。
- 查詢排名為 \(x\) 的數(如果不存在,則認為是排名小於 \(x\) 的最大數。保證 \(x\) 不會超過當前資料結構中數的總數)。
- 求 \(x\) 的前驅(前驅定義為小於 \(x\),且最大的數)。
- 求 \(x\) 的後繼(後繼定義為大於 \(x\),且最小的數)。
本題強制線上,保證所有操作合法(操作 \(2\) 保證存在至少一個 \(x\),操作 \(4,5,6\) 保證存在答案)。
輸入輸出格式
輸入格式
第一行兩個正整數 $n,m$,表示**初始數的個數**和操作的個數。
第二行 \(n\) 個整數 \(a_1,a_2,a_3,\ldots,a_n\),表示初始的數。
接下來 \(m\) 行,每行有兩個整數 \(\text{opt}\) 和 \(x'\),\(\text{opt}\)
我們記 \(\text{last}\) 表示上一次 \(3,4,5,6\) 操作的答案,則每次操作的 \(x'\) 都要異或上 \(\text{last}\) 才是真實的 \(x\)。初始 \(\text{last}\) 為 \(0\)。
輸出格式
輸出一行一個整數,表示所有 $3,4,5,6$ 操作的答案的**異或和**。
輸入輸出樣例
輸入樣例 #1
6 7 1 1 4 5 1 4 2 1 1 9 4 1 5 8 3 13 6 7 1 4
輸出樣例 #1
6
說明
### 樣例解釋樣例加密前為:
6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 9
3 8
6 1
1 0
限制與約定
對於 \(100\%\) 的資料,\(1\leq n\leq 10^5\),\(1\leq m\leq 10^6\),\(0\leq a_i,x\lt 2^{30}\)。
本題輸入資料較大,請使用較快的讀入方式。
#include <bits/stdc++.h>
using namespace std;
#define getsize(x) (x ? x -> size : 0)
#define ll long long
const int MAXN = 1e6 + 10;
#define USE_FREAD // 使用 fread 讀入,去註釋符號
#define USE_FWRITE // 使用 fwrite 輸出,去註釋符號
#ifdef USE_FREAD
namespace iB
{
char buf[1 << 21], *p1 = buf, *p2 = buf;
}
#define getchar() (iB::p1 == iB::p2 && (iB::p2 = (iB::p1 = iB::buf) + fread(iB::buf, 1, 1 << 21, stdin), iB::p1 == iB::p2) ? EOF : *iB::p1++)
#endif
#ifdef USE_FWRITE
namespace oB
{
char buf[1 << 21], *p1 = buf, *p2 = buf + (1 << 21);
}
#define putchar(ch) ((oB::p1 == oB::p2 && fwrite(oB::p1 = oB::buf, 1, 1 << 21, stdout)), *oB::p1++ = ch)
#endif
namespace Fastio
{
struct Reader
{
char endch;
Reader()
{
endch = '\0';
}
Reader& operator >> (char &ch) // ignore character ' ', '\r', '\n', '\t'
{
ch = getchar();
while (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t') ch = getchar();
return *this;
}
Reader& operator >> (char *str)
{
while (((*str = getchar()) == ' ' || *str == '\n' || *str == '\r' || *str == '\t') && *str != EOF);
while ((*++str = getchar()) != ' ' && *str != '\n' && *str != '\r' && *str != '\t' && *str != EOF);
*str = '\0';
return *this;
}
template <typename Int>
Reader& operator >> (Int &d)
{
bool flag = 0;
endch = getchar();
while ((!isdigit(endch)) && endch != '-' && endch != EOF) endch = getchar();
if (endch == '-') flag = 1, endch = getchar();
d = endch & 15;
while (isdigit(endch = getchar())) d = (d << 3) + (d << 1) + (endch & 15);
if (flag) d = -d;
return *this;
}
template <typename T>
inline T get()
{
T Val;
(*this) >> Val;
return Val;
}
};
struct Writer
{
~Writer()
{
#ifdef USE_FWRITE
fwrite(oB::buf, 1, oB::p1 - oB::buf, stdout);
#endif
}
Writer& operator << (const char ch)
{
putchar(ch);
return *this;
}
Writer& operator << (const char *ch)
{
while (*ch) putchar(*(ch++));
return *this;
}
Writer& operator << (char* ss)
{
return *this << (const char *)ss;
}
template <typename Int>
Writer& operator << (Int x)
{
static char buffer[33];
static int top = 0;
if (!x)
{
putchar('0');
return *this;
}
if (x < 0) putchar('-'), x = -x;
while (x)
{
buffer[++top] = '0' | (x % 10);
x /= 10;
}
while (top) putchar(buffer[top--]);
return *this;
}
};
void flush_output()
{
#ifdef USE_FWRITE
fwrite(oB::buf, 1, oB::p1 - oB::buf, stdout);
oB::p1 = oB::buf;
#else
fflush(stdout);
#endif
}
}
Fastio::Reader kin;
Fastio::Writer kout;
class FHQ
{
public :
class Node
{
public :
ll key, rank;
int size;
Node *ls, *rs;
void push_up()
{
size = getsize(ls) + getsize(rs) + 1;
}
}pool[2 * MAXN], *rt;
int top;
//分裂 p 返回 p 的左子p_l, 右子p_r
void split(Node *p , Node *&p_l, Node *&p_r, int x)//分裂當前子樹
{
if(!p)//p 為空,無需分離
{
p_l = p_r = NULL;
return ;
}
if(p -> key <= x)//如果 p 的值比 x 小,就把 p 接到左子上,繼續分裂 p 的右子
{
p_l = p;
split(p -> rs, p_l -> rs, p_r, x);
p_l -> push_up();
}
else//否則分 p 的左子
{
p_r = p;
split(p -> ls, p_l ,p_r -> ls, x);
p_r -> push_up();
}
}
void merge(Node *&p, Node *p_l, Node *p_r)
{
if(!p_l || !p_r)
{
p = p_l ? p_l : p_r;
return ;
}
if(p_l -> rank < p_r -> rank)
{
p = p_l;
merge(p -> rs, p_l -> rs, p_r);
}
else
{
p = p_r;
merge(p -> ls, p_l, p_r -> ls);
}
p -> push_up();
}
Node *newNode(int x)
{
Node *p = pool + (++top);
p -> key = x;
p -> rank = rand();
p -> size = 1;
return p;
}
void insert(Node *&rt, int x)
{
Node *p1, *p2;
split(rt, p1, p2 ,x - 1);
merge(rt, p1 ,newNode(x));
merge(rt, rt, p2);
}
void remove(Node *&rt, int x)
{
Node *p1, *p2, *p3 , *p4;
split(rt, p1 ,p2 ,x - 1);
split(p2, p3 ,p4, x);
merge(p3, p3 -> ls, p3 -> rs);
merge(p3, p3, p4);
merge(rt, p1, p3);
}
ll getRank(Node *&rt, int x)
{
Node *p1 ,*p2;
split(rt, p1 ,p2, x - 1);
ll ans = getsize(p1);
merge(rt, p1 ,p2);
return ans;
}
ll getKey(Node *p, ll rank)
{
while(p)
{
if(rank <= getsize(p -> ls))
p = p -> ls;
else if(rank > getsize(p -> ls) + 1)
{
rank -= getsize(p -> ls) + 1;
p = p -> rs;
}
else return p -> key;
}
return 0;
}
ll lower(Node *p, ll x)
{
ll ans = INT_MIN;
while(p)
{
if(x > p -> key)
{
ans = max(ans, p -> key);
p = p -> rs;
}
else p = p -> ls;
}
return ans;
}
ll upper(Node *p, int x)
{
ll ans = INT_MAX;
while(p)
{
if(x < p -> key)
{
ans = min(ans, p -> key);
p = p -> ls;
}
else p = p -> rs;
}
return ans;
}
}FHQ;
int t;
int op;
ll x;
long long ans;
int n;
ll last;
int main()
{
// scanf("%d %d", &n,&t);
kin >> n >> t;
for(int i = 1; i <= n; i++)
{
//scanf("%lld", &x);
kin >> x;
FHQ.insert(FHQ.rt, x);
}
while(t--)
{
//scanf("%d %lld", &op, &x);
kin >> op >> x;
x ^= last;
if(op == 1)
{
FHQ.insert(FHQ.rt, x);
}
if(op == 2)
{
FHQ.remove(FHQ.rt, x);
}
if(op == 3)
{
last = FHQ.getRank(FHQ.rt, x) + 1;
ans ^= last;
}
if(op == 4)
{
last = FHQ.getKey(FHQ.rt, x);
ans ^= last;
}
if(op == 5)
{
last = FHQ.lower(FHQ.rt, x);
ans ^= last;
}
if(op == 6)
{
last = FHQ.upper(FHQ.rt, x);
ans ^= last;
}
// printf("%lld\n", last);
}
kout << ans;
//printf("%lld", ans);
return 0;
}