二次联通门 : LibreOJ #106. 二逼平衡树
/* LibreOJ #106. 二逼平衡树 写了整整一下午 1遍AC 感人肺腑啊。。。 我的做法比较中规中矩 线段树套splay 对于操作1没什么好说, 在线段树查询区间时查出排名 对于操作2, 一开始没想太多 在写完基础函数时突然意识到不好做 在想不出好办法后看了题解, 得知了要用二分 二分一下这个数, 二分出一个答案查排名 然后找前驱即可 操作3要在splay中删除再插入即可 操作4, 5没什么可说的。。。。。。 这个写法不太好。。 既然封装了。。。就要考虑一下充分利用封装的好处啊。。 */ #include <cstdio> #define Max 4000005 #define INF 1e9 void read (int &now) { register char word = getchar (); bool temp = false; for (now = 0; word < ‘0‘ || word > ‘9‘; word = getchar ()) if (word == ‘-‘) temp = true; for (; word >= ‘0‘ && word <= ‘9‘; now = now * 10 + word - ‘0‘, word = getchar ()); if (temp) now = -now; } int data[Max]; struct S_D { S_D *child[2], *father; int size, weigth; int key; S_D () { this->child[0] = this->child[1] = NULL; this->father = NULL; this->size = this->weigth = 1; this->key = 0; } void Clear () { this->child[0] = this->child[1] = NULL; this->father = NULL; } int Get_Pos () { return this->father->child[1] == this; } inline void Updata () { this->size = this->weigth; if (this->child[0]) this->size += this->child[0]->size; if (this->child[1]) this->size += this->child[1]->size; } }; int Maxn = -INF; inline int max (int a, int b) { return a > b ? a : b; } inline int min (int a, int b) { return a < b ? a : b; } struct X_D { X_D *Left, *Right; int l, r; int Mid; X_D (int __l, int __r) : l (__l), r (__r) { Left = Right = NULL; Mid = __l + __r >> 1; } }; int Answer; class Splay_Tree_Type { private : S_D *root[Max]; void Rotate (S_D *now) { S_D *Father = now->father; int pos = now->Get_Pos () ^ 1; Father->child[pos ^ 1] = now->child[pos]; if (now->child[pos]) now->child[pos]->father = Father; if ((now->father = Father->father) != NULL) now->father->child[now->father->child[1] == Father] = now; Father->father = now; now->child[pos] = Father; Father->Updata (); now->Updata (); } void Splay (S_D *now) { for (S_D *Father; Father = now->father; this->Rotate (now)) if (Father->father) this->Rotate (now->Get_Pos () == Father->Get_Pos () ? Father : now); } public : void Insert (int pos, int x) { if (root[pos] == NULL) { root[pos] = new S_D ; root[pos]->key = x; return ; } S_D *now = root[pos], *Father; for (; ; Father = now, now = now->child[x > now->key]) { if (now == NULL) { now = new S_D; now->father = Father; now->key = x; Father->child[x > Father->key] = now; this->Splay (now); root[pos] = now; return ; } if (now->key == x) { now->weigth ++; this->Splay (now); root[pos] = now; return ; } } } int Find_Rank (int pos, int x) { S_D *now = root[pos]; int Answer = 0; for (; ; ) { if (now == NULL) return Answer; if (now->key == x) return (now->child[0] ? now->child[0]->size : 0) + Answer; else if (now->key < x) { Answer += (now->child[0] ? now->child[0]->size : 0) + now->weigth; now = now->child[1]; } else if (now->key > x) now = now->child[0]; } } void Find (int pos, int x) { S_D *now; for (now = root[pos]; (now != NULL && x != now->key); now = now->child[x > now->key]); this->Splay (now); root[pos] = now; return ; } void Delete (int pos) { S_D *now = root[pos]; if (now->weigth > 1) { now->weigth --; now->size --; return ; } if (now->child[0] == NULL && now->child[1] == NULL) { root[pos] = NULL; now->Clear (); return ; } S_D *res; if (now->child[1] == NULL) { res = now; now->child[0]->father = NULL; root[pos] = now->child[0]; res->Clear (); return ; } if (now->child[0] == NULL) { res = now; now->child[1]->father = NULL; root[pos] = now->child[1]; res->Clear (); return ; } res = root[pos]; S_D *res_pre = Find_Prefix_Pos (pos); this->Splay (res_pre); root[pos] = res_pre; root[pos]->child[1] = res->child[1]; res->child[1]->father = root[pos]; res->Clear (); root[pos]->Updata (); return; } S_D *Find_Prefix_Pos (int pos) { S_D *now = root[pos]; for (now = now->child[0]; now->child[1]; now = now->child[1]); return now; } int Ask_Prefix (int pos, int x) { S_D *now = root[pos]; for (; now;) { if (now->key < x) { if (Answer < now->key) Answer = now->key; now = now->child[1]; } else now = now->child[0]; } return Answer; } int Ask_Suffix (int pos, int x) { S_D *now = root[pos]; for (; now; ) { if (now->key > x) { if (Answer > now->key) Answer = now->key; now = now->child[0]; } else now = now->child[1]; } return Answer; } }; Splay_Tree_Type Splay; class Segment_Tree_Type { private : X_D *Root; void __Build_ (X_D *&now, int l, int r) { now = new X_D (l, r); if (l == r) return ; __Build_ (now->Left, l, now->Mid); __Build_ (now->Right, now->Mid + 1, r); } void __Insert_ (X_D *&now, int pos, int x, int _in) { Splay.Insert (_in, x); if (now->l == now->r) return ; if (pos <= now->Mid) __Insert_ (now->Left, pos, x, _in << 1); else __Insert_ (now->Right, pos, x, _in << 1 | 1); } void __Query_Rank_ (X_D *&now, int l, int r, int k, int _in) { if (l <= now->l && now->r <= r) { Answer += Splay.Find_Rank (_in, k); return ; } if (l <= now->Mid) __Query_Rank_ (now->Left, l, r, k, _in << 1); if (now->Mid < r) __Query_Rank_ (now->Right, l, r, k, _in << 1 | 1); } void __Change_ (X_D *&now, int pos, int x, int _in) { Splay.Find (_in, data[pos]); Splay.Delete (_in); Splay.Insert (_in, x); if (now->l == now->r) return ; if (pos <= now->Mid) __Change_ (now->Left, pos, x, _in << 1); else __Change_ (now->Right, pos, x, _in << 1 | 1); } void __Query_Prefix_ (X_D *&now, int l, int r, int x, int _in) { if (l <= now->l && now->r <= r) { Answer = max (Answer, Splay.Ask_Prefix (_in, x)); return ; } if (l <= now->Mid) __Query_Prefix_ (now->Left, l, r, x, _in << 1); if (now->Mid < r) __Query_Prefix_ (now->Right, l, r, x, _in << 1 | 1); } void __Query_Suffix_ (X_D *&now, int l, int r, int x, int _in) { if (l <= now->l && now->r <= r) { Answer = min (Answer, Splay.Ask_Suffix (_in, x)); return ; } if (l <= now->Mid) __Query_Suffix_ (now->Left, l, r, x, _in << 1); if (r > now->Mid) __Query_Suffix_ (now->Right, l, r, x, _in << 1 | 1); } public : void Build (int l, int r) { __Build_ (Root, l, r); return ; } void Insert (int pos, int x) { __Insert_ (Root, pos, x, 1); return ; } int Query_Suffix (int l, int r, int k) { Answer = INF; __Query_Suffix_ (Root, l, r, k, 1); return Answer; } int Query_kth_number (int l, int r, int x) { int L, R, Mid; for (L = 0, R = Maxn + 1, Mid; L != R; ) { Mid = L + R >> 1; Answer = 0; this->Query_Rank (l, r, Mid); if (Answer < x) L = Mid + 1; else R = Mid; } return L - 1; } int Query_Rank (int l, int r, int k) { Answer = 0; __Query_Rank_(Root, l, r, k, 1); return Answer; } int Query_Prefix (int l, int r, int k) { Answer = 0; __Query_Prefix_ (Root, l, r, k, 1); return Answer; } void Change (int pos, int x) { __Change_ (Root, pos, x, 1); return ; } }; Segment_Tree_Type Seg; int main (int argc, char *argv[]) { int N, M; read (N); read (M); Seg.Build (1, N); for (int i = 1; i <= N; i ++) { read (data[i]); Maxn = max (data[i], Maxn); Seg.Insert (i, data[i]); } for (int type, x, y, z; M --; ) { read (type); if (type == 1) { read (x); read (y); read (z); printf ("%d\n", Seg.Query_Rank (x, y, z) + 1); } else if (type == 2) { read (x); read (y); read (z); printf ("%d\n", Seg.Query_kth_number (x, y, z)); } else if (type == 3) { read (x); read (z); Seg.Change (x, z); data[x] = z; Maxn = max (Maxn, x); } else if (type == 4) { read (x); read (y); read (z); printf ("%d\n", Seg.Query_Prefix (x, y, z)); } else { read (x); read (y); read (z); printf ("%d\n", Seg.Query_Suffix (x, y, z)); } } return 0; }
时间: 2024-10-23 05:33:00