日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

二逼平衡树——树套树(线段树套Splay平衡树)

發(fā)布時間:2023/11/27 生活经验 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二逼平衡树——树套树(线段树套Splay平衡树) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題面

  Bzoj3196

解析

  線段樹和Splay兩棵樹套在一起,常數(shù)直逼inf,但最終僥幸過了

  思路還是比較簡單, 在原數(shù)組維護一個下標線段樹,再在每一個線段樹節(jié)點,維護一個對應(yīng)區(qū)間的權(quán)值Splay。簡單說一下操作:

 0.提取區(qū)間

  這個操作是1、2、4、5操作的基礎(chǔ),其實也比較容易實現(xiàn),在線段樹中跑一跑,如果詢問區(qū)間包含了節(jié)點覆蓋的區(qū)間,就在一個數(shù)組中存一下節(jié)點的編號,然后返回就行

 1.查詢區(qū)間內(nèi)k的排名

  提取區(qū)間,找到區(qū)間內(nèi)所有的Splay, 分別比k小的數(shù)的個數(shù),相加后加一即可

 2.查詢區(qū)間第k大

  提取區(qū)間,找到區(qū)間內(nèi)所有的Splay,因為有多棵Splay,這個操作顯然不能像一般的Splay一樣查詢,只能二分答案,轉(zhuǎn)化為操作一,再check排名就行

 3.單點修改

  先在線段樹中向下找到包含pos的所有節(jié)點,將這些節(jié)點對應(yīng)的Splay中原值刪去, 加入新值即可

 4.求前驅(qū)

  同樣找到區(qū)間內(nèi)的所有Splay,分別進入找前驅(qū),輸出最大的前驅(qū)即可。但k可能不在Splay中,于是我們先要找到大于等于k的權(quán)值最小的節(jié)點,將它旋轉(zhuǎn)到根,再找前驅(qū),但由于可能沒有前驅(qū),就在每棵Splay插入-inf, 查詢排名時記得減去即可

 5.求后繼

  操作與前驅(qū)類似,找到小于等于k的權(quán)值最大的節(jié)點,旋轉(zhuǎn)到根,找后繼,記得每棵Splay插入inf就行

?

  大部分操作都是自己YY的,可能不是很優(yōu)秀,但我這個又臭又長的代碼并沒有調(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平衡树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。