二逼平衡树——树套树(线段树套Splay平衡树)
題面
Bzoj3196
解析
線段樹和Splay兩棵樹套在一起,常數(shù)直逼inf,但最終僥幸過了
思路還是比較簡(jiǎn)單, 在原數(shù)組維護(hù)一個(gè)下標(biāo)線段樹,再在每一個(gè)線段樹節(jié)點(diǎn),維護(hù)一個(gè)對(duì)應(yīng)區(qū)間的權(quán)值Splay。簡(jiǎn)單說一下操作:
0.提取區(qū)間
這個(gè)操作是1、2、4、5操作的基礎(chǔ),其實(shí)也比較容易實(shí)現(xiàn),在線段樹中跑一跑,如果詢問區(qū)間包含了節(jié)點(diǎn)覆蓋的區(qū)間,就在一個(gè)數(shù)組中存一下節(jié)點(diǎn)的編號(hào),然后返回就行
1.查詢區(qū)間內(nèi)k的排名
提取區(qū)間,找到區(qū)間內(nèi)所有的Splay, 分別比k小的數(shù)的個(gè)數(shù),相加后加一即可
2.查詢區(qū)間第k大
提取區(qū)間,找到區(qū)間內(nèi)所有的Splay,因?yàn)橛卸嗫肧play,這個(gè)操作顯然不能像一般的Splay一樣查詢,只能二分答案,轉(zhuǎn)化為操作一,再check排名就行
3.單點(diǎn)修改
先在線段樹中向下找到包含pos的所有節(jié)點(diǎn),將這些節(jié)點(diǎn)對(duì)應(yīng)的Splay中原值刪去, 加入新值即可
4.求前驅(qū)
同樣找到區(qū)間內(nèi)的所有Splay,分別進(jìn)入找前驅(qū),輸出最大的前驅(qū)即可。但k可能不在Splay中,于是我們先要找到大于等于k的權(quán)值最小的節(jié)點(diǎn),將它旋轉(zhuǎn)到根,再找前驅(qū),但由于可能沒有前驅(qū),就在每棵Splay插入-inf, 查詢排名時(shí)記得減去即可
5.求后繼
操作與前驅(qū)類似,找到小于等于k的權(quán)值最大的節(jié)點(diǎn),旋轉(zhuǎn)到根,找后繼,記得每棵Splay插入inf就行
?
大部分操作都是自己YY的,可能不是很優(yōu)秀,但我這個(gè)又臭又長(zhǎng)的代碼并沒有調(diào)試多久,也是不容易啊。
代碼(340行):
#include<bits/stdc++.h> using namespace std; const int maxn = 100005, inf = 2147483647;template<class T> void read(T &re) {re=0;T sign=1;char tmp;while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');re*=sign; }int n, m, root[maxn<<1], rt, a[maxn]; int tot, cnt, lson[maxn<<1], rson[maxn<<1], stak[maxn], top, s[maxn], snum;struct Splay_tree{int fa, s[2], val, siz, num; }tr[maxn * 20];void update(int x) {int ls = tr[x].s[0], rs = tr[x].s[1];tr[x].siz = tr[ls].siz + tr[rs].siz + tr[x].num; }void Rotate(int x) {int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];tr[y].s[k] = son;tr[son].fa = y;tr[x].s[k^1] = y;tr[y].fa = x;tr[z].s[w] = x;tr[x].fa = z;update(y);update(x); }void Splay(int x, int to, int id) {int y, z;while(tr[x].fa != to){y = tr[x].fa;z = tr[y].fa;if(z != to)Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);Rotate(x);}if(!to)root[id] = x; }void Insert(int x, int v) {int now = root[x], ff = 0;while(now){ff = now;tr[now].siz ++;if(tr[now].val == v) break;now = tr[now].s[v>tr[now].val];}if(now)tr[now].num ++;else{if(snum)now = s[snum--];elsenow = ++cnt;tr[now].val = v;tr[ff].s[v>tr[ff].val] = now;tr[now].fa = ff;tr[now].num = 1;tr[now].siz = 1;tr[now].s[0] = tr[now].s[1] = 0;}Splay(now, 0, x); }void build(int &x, int l, int r) {x = ++tot;root[x] = ++cnt;tr[root[x]].val = -inf;tr[root[x]].siz = tr[root[x]].num = 1;tr[0].s[1] = root[x];Insert(x, inf);for(int i = l; i <= r; ++i)Insert(x, a[i]);if(l == r) return ;int mid = (l + r)>>1;build(lson[x], l, mid);build(rson[x], mid + 1, r); }void Extract(int x, int l, int r, int L, int R) {if(l <= L && R <= r){stak[++top] = x;return ;}int mid = (L + R)>>1;if(l <= mid)Extract(lson[x], l, r, L, mid);if(mid < r)Extract(rson[x], l, r, mid + 1, R); }int Queryrk(int id, int x) {int now = root[id], ret = 0;while(now){int ls = tr[now].s[0], rs = tr[now].s[1];if(x < tr[now].val){if(ls)now = ls;elsebreak;} else if(x == tr[now].val){ret += tr[ls].siz ;break;}else{ret += tr[ls].siz + tr[now].num;if(rs)now = rs;elsebreak;}}tr[0].s[1] = root[id];Splay(now, 0, id);return ret; }int work1(int x) {int ret = -top;while(top){ret += Queryrk(stak[top], x);top --;}return ret + 1; }int check(int x) {int ret = 0;for(int i = 1; i <= top; ++i)ret += Queryrk(stak[i], x);return ret + 1; }int work2(int x) {x += top;int l = 0, r = 1e8, mid, ret = 0;while(l <= r){mid = (l + r)>>1;if(check(mid) <= x)ret = mid, l = mid + 1;elser = mid - 1;}top = 0;return ret; }int Find(int now, int x) {while(1){int ls = tr[now].s[0], rs = tr[now].s[1];if(tr[now].val == x) return now;if(x < tr[now].val) now = ls;else now = rs;} }int Querypre(int now) {now = tr[now].s[0];while(tr[now].s[1]) now = tr[now].s[1];return now; }int Querynxt(int now) {now = tr[now].s[1];while(tr[now].s[0]) now = tr[now].s[0];return now; }void Modify(int x, int pos, int l, int r, int v) {tr[0].s[1] = root[x];int y = Find(root[x], a[pos]);Splay(y, 0, x);int pre = Querypre(root[x]);int nxt = Querynxt(root[x]);Splay(pre, 0, x);Splay(nxt, pre, x);if(tr[y].num > 1){tr[y].num --;tr[y].siz --;}else{s[++snum] = y;tr[nxt].s[0] = 0;}update(nxt);update(pre);Insert(x, v);if(l == r){a[pos] = v;return ;}int mid = (l + r)>>1;if(pos <= mid)Modify(lson[x], pos, l, mid, v);elseModify(rson[x], pos, mid + 1, r, v); }int Findmx(int now, int x) {int ret = 0;while(now){int ls = tr[now].s[0], rs = tr[now].s[1];if(tr[now].val == x)return now;if(tr[now].val > x){ret = now;now = ls;}elsenow = rs;}return ret; }int Findmn(int now, int x) {int ret = 0;while(now){int ls = tr[now].s[0], rs = tr[now].s[1];if(tr[now].val == x)return now;if(tr[now].val < x){ret = now;now = rs;}elsenow = ls;}return ret; }int work3(int x) {int ret = -inf;while(top){tr[0].s[1] = root[stak[top]];int now = Findmx(root[stak[top]], x);Splay(now, 0, stak[top]);int pre = Querypre(root[stak[top]]);ret = max(ret, tr[pre].val);top--;}return ret; }int work4(int x) {int ret = inf;while(top){tr[0].s[1] = root[stak[top]];int now = Findmn(root[stak[top]], x);Splay(now, 0, stak[top]);int nxt = Querynxt(root[stak[top]]);ret = min(ret, tr[nxt].val);top--;}return ret; }int main() {read(n);read(m);for(int i = 1; i <= n; ++i)read(a[i]);build(rt, 1, n);for(int i = 1; i <= m; ++i){int opt, l, r, k, pos;read(opt);if(opt == 1){read(l);read(r);read(k);Extract(rt, l, r, 1, n);printf("%d\n", work1(k));}else if(opt == 2){read(l);read(r);read(k);Extract(rt, l, r, 1, n);printf("%d\n", work2(k));}else if(opt == 3){read(pos);read(k);Modify(rt, pos, 1, n, k);}else if(opt == 4){read(l);read(r);read(k);Extract(rt, l, r, 1, n);printf("%d\n", work3(k));}else{read(l);read(r);read(k);Extract(rt, l, r, 1, n);printf("%d\n", work4(k));}}return 0; }View Code
?
轉(zhuǎn)載于:https://www.cnblogs.com/Joker-Yza/p/11243378.html
總結(jié)
以上是生活随笔為你收集整理的二逼平衡树——树套树(线段树套Splay平衡树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: TMS Scripter importt
- 下一篇: Speed4Web 绿色纯净版
