洛谷 P3369 【模板】普通平衡树
生活随笔
收集整理的這篇文章主要介紹了
洛谷 P3369 【模板】普通平衡树
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原題地址:https://www.luogu.org/problemnew/show/P3369
題目描述
您需要寫一種數(shù)據(jù)結(jié)構(gòu)(可參考題目標(biāo)題),來(lái)維護(hù)一些數(shù),其中需要提供以下操作:
輸入輸出格式
輸入格式:
?
第一行為nn,表示操作的個(gè)數(shù),下面nn行每行有兩個(gè)數(shù)optopt和xx,optopt表示操作的序號(hào)(?1 \leq opt \leq 61≤opt≤6?)
?
輸出格式:
?
對(duì)于操作3,4,5,63,4,5,6每行輸出一個(gè)數(shù),表示對(duì)應(yīng)答案
?
輸入輸出樣例
輸入樣例#1:?
10 1 106465 4 1 1 317721 1 460929 1 644985 1 84185 1 89851 6 81968 1 492737 5 493598輸出樣例#1:?
106465 84185 492737說(shuō)明
時(shí)空限制:1000ms,128M
1.n的數(shù)據(jù)范圍:?n \leq 100000n≤100000
2.每個(gè)數(shù)的數(shù)據(jù)范圍:?[-{10}^7, {10}^7][?107,107]
來(lái)源:Tyvj1728 原名:普通平衡樹(shù)
在此鳴謝
splay代碼如下
#include <iostream> #include <cstdio> #define maxn 100005 #define INF 100000000 using namespace std; int root; int point; int p; //當(dāng)前還有幾個(gè)節(jié)點(diǎn) struct splay{int father; //父節(jié)點(diǎn) int child[2]; //左孩子,右孩子 int recy, sum; //data出現(xiàn)次數(shù),左右孩子的數(shù)據(jù)總數(shù)+recy int data; //數(shù)據(jù) }tree[maxn]; void connect(int father, int son, int i) //使son成為father的孩子 {tree[son].father = father;tree[father].child[i] = son; } bool get(int x) //是其根節(jié)點(diǎn)的左孩子還是右孩子 {int father = tree[x].father;return tree[father].child[1] == x; } void update(int x) //更新sum {tree[x].sum = tree[tree[x].child[0]].sum + tree[tree[x].child[1]].sum + tree[x].recy; } void rotate(int x) //旋轉(zhuǎn) {int y = tree[x].father;int z = tree[y].father;int u = get(x);int v = get(y);connect(y, tree[x].child[u^1], u);connect(z, x, v);connect(x, y, u^1);update(y);update(x); } void splay(int now, int to) //把now旋轉(zhuǎn)到to位置 {if(to == root) //root = now;to = tree[to].father;while(tree[now].father != to){int up = tree[now].father;if(tree[up].father == to)rotate(now);else if(get(now) == get(up)){rotate(up);rotate(now);}else {rotate(now);rotate(now);}} } int crepoint(int v, int fa) {point ++;tree[point].data = v;tree[point].child[0] = tree[point].child[1] = 0;tree[point].father = fa;tree[point].sum = tree[point].recy = 1;return point; } int insert(int v) {if(p == 0){ //如果沒(méi)有節(jié)點(diǎn)了 root = crepoint(v, 0);return root;}int now = root;while(true){tree[now].sum ++; //進(jìn)過(guò)的每一個(gè)點(diǎn)都sum++ if(tree[now].data == v){tree[now].recy ++; return now;}else {int t = tree[now].data < v;if(tree[now].child[t] == 0){int son = crepoint(v, now);tree[now].child[t] = son;return son;}now = tree[now].child[t];}}return 0; } void push(int v) {int t = insert(v);splay(t, root);p ++; } void del(int x) {tree[x].child[0] = tree[x].child[1] = tree[x].data = tree[x].father = tree[x].recy = tree[x].sum = 0; } void pop(int v) {int now = root;while(now != 0){if(v == tree[now].data){splay(now, root); //把要?jiǎng)h除的節(jié)點(diǎn)旋轉(zhuǎn)到根 if(tree[now].recy > 1){tree[now].recy --;tree[now].sum --;} else { if(!tree[now].child[0]){ //如果沒(méi)有左子樹(shù),直接刪掉此節(jié)點(diǎn),然后把右孩子設(shè)為根節(jié)點(diǎn) root = tree[now].child[1];tree[root].father = 0;}else {int left = tree[now].child[0];while(tree[left].child[1]) //找到左子樹(shù)的最大值節(jié)點(diǎn) left = tree[left].child[1];splay(left, tree[now].child[0]); //把左子樹(shù)最大節(jié)點(diǎn)旋轉(zhuǎn)到根節(jié)點(diǎn)左孩子的位置 connect(left, tree[now].child[1], 1); //讓左子樹(shù)最大節(jié)點(diǎn)作為新的根 update(left); //連接后更新 root = left;tree[root].father = 0;}del(now); //刪除節(jié)點(diǎn) }p --;return;}else {int t = tree[now].data < v;now = tree[now].child[t];}} } int rnk(int v) //返回v是第幾大 {int now = root;int r = 0;while(true){int left = tree[now].child[0];if(tree[now].data == v){r = r + tree[left].sum + 1;splay(now, root); //旋轉(zhuǎn)后left。sum的值會(huì)變 return r;}else if(tree[now].data < v){r += tree[left].sum + tree[now].recy;now = tree[now].child[1];}else now = tree[now].child[0];} } int atrank(int n) //返回第n大的數(shù) {int now = root;while(true){int left = tree[now].child[0];if(tree[left].sum >= n){now = left;}else if(tree[left].sum + tree[now].recy < n){n -= tree[left].sum + tree[now].recy;now = tree[now].child[1];}else {splay(now, root); //旋轉(zhuǎn)到根 return tree[now].data;} } } int lower(int v) //前驅(qū) {int ans = -INF; int now = root;while(now){//cout << "!! " << now << " " << tree[now].data << endl;//if(tree[now].data < v && tree[now].data > ans)ans = tree[now].data;if(tree[now].data >= v)now = tree[now].child[0];elsenow = tree[now].child[1];}return ans; } int upper(int v) //后繼 {int ans = INF;int now = root;while(now){if(tree[now].data > v && tree[now].data < ans)ans = tree[now].data;if(tree[now].data <= v)now = tree[now].child[1];elsenow = tree[now].child[0];}return ans; } int main() {int n;cin >> n;for(int i = 0; i < n; i ++){int opt, x;scanf("%d%d", &opt, &x);//cin >> opt >> x;if(opt == 1){push(x);}else if(opt == 2){pop(x);}else if(opt == 3){printf("%d\n", rnk(x));//cout << rnk(x) << endl;}else if(opt == 4){printf("%d\n", atrank(x));}else if(opt == 5){printf("%d\n", lower(x));}else {printf("%d\n", upper(x));}}return 0; }7.12更新
常數(shù)更小更容易寫的LeafyTree代碼如下:
#include <bits/stdc++.h> #define INF 0x3f3f3f3f #define ratio 4 using namespace std; typedef long long ll;inline int read(){int res = 0, w = 0; char ch = 0;while(!isdigit(ch)){w |= ch == '-', ch = getchar();}while(isdigit(ch)){res = (res << 3) + (res << 1) + (ch ^ 48);ch = getchar();}return w ? -res : res; }const int N = 100005;int siz[N << 2], data[N << 2], lch[N << 2], rch[N << 2]; int cnt, root;void merge(int l, int r) {++cnt;siz[cnt] = siz[l] + siz[r];data[cnt] = data[r]; lch[cnt] = l;rch[cnt] = r; }void rotate(int k, bool flg) {if(flg){merge(rch[lch[k]], rch[k]);lch[k] = lch[lch[k]];rch[k] = cnt;}else {merge(lch[k], lch[rch[k]]);lch[k] = cnt;rch[k] = rch[rch[k]];} }void maintain(int k) {if(siz[lch[k]] > siz[rch[k]] * ratio)rotate(k, 1);else if(siz[rch[k]] > siz[lch[k]] * ratio)rotate(k, 0); }int newnode(int v) {++cnt;siz[cnt] = 1;data[cnt] = v;return cnt; }void pushup(int k) {if(siz[lch[k]] == 0)return;siz[k] = siz[lch[k]] + siz[rch[k]];data[k] = data[rch[k]]; }void insert(int k, int x) {if(siz[k] == 1){lch[k] = newnode(min(data[k], x));rch[k] = newnode(max(data[k], x));pushup(k);return;}insert(x <= data[lch[k]] ? lch[k] : rch[k], x);maintain(k);pushup(k); }void cpynode(int a, int b) {siz[a] = siz[b];data[a] = data[b];lch[a] = lch[b];rch[a] = rch[b]; }void del(int k, int fa, int x) {if(siz[k] == 1){cpynode(fa, k == lch[fa] ? rch[fa] : lch[fa]);return;}del(x <= data[lch[k]] ? lch[k] : rch[k], k, x);maintain(k);pushup(k); }int rnk(int k, int x) {if(siz[k] == 1)return 1;if(x <= data[lch[k]])return rnk(lch[k], x);else return rnk(rch[k], x) + siz[lch[k]]; }int atrank(int k, int x) {if(siz[k] == x)return data[k];if(x > siz[lch[k]])return atrank(rch[k], x - siz[lch[k]]);elsereturn atrank(lch[k], x); }int lower(int x) {return atrank(root, rnk(root, x) - 1); }int upper(int x) {return atrank(root, rnk(root, x + 1)); }int main() {int n;scanf("%d", &n);root = newnode(INF);for(int i = 1; i <= n; i ++){int opt, x;scanf("%d%d", &opt, &x);if(opt == 1)insert(root, x);else if(opt == 2)del(root, 0, x);else if(opt == 3)printf("%d\n", rnk(root, x));else if(opt == 4)printf("%d\n", atrank(root, x));else if(opt == 5)printf("%d\n", lower(x));else if(opt == 6)printf("%d\n", upper(x));}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的洛谷 P3369 【模板】普通平衡树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 练习4闭合导线平差计算
- 下一篇: 1对1实时视频/语音通讯原理概述