洛谷 P3380 模板 二逼平衡樹(樹套樹)

2022-05-06 22:09:13 字數 1765 閱讀 9063

其實比想象中的好理解啊

所謂樹套樹,就是在一棵樹的基礎上,每乙個節點再維護一棵樹

說白了,就是為了實現自己想要的操作和優秀的時間複雜度,來人為的增加一些毒瘤資料結構來維護一些什麼東西

比如說這道題

如果只求乙個區間內的乙個數是否是最大值或者最小值,我們顯然可以用線段樹輕輕鬆鬆地解決這個問題

但是現在我們要求乙個區間內乙個數是否是k大值,那麼這個東西我們就可以很顯然的用平衡樹來解決這個問題

即對每乙個區間都單獨維護一棵平衡樹,然後利用線段樹的外殼,將得到的各個區間內的答案進行合併

然後,這道題除了碼量極大,常數極難卡,好像就沒有什麼可以做的了

好了,還是來說一下每乙個操作的具體做法

操作一,就像上文所說的那樣,對每乙個與詢問區間有關的區間進行求\(rank\)操作,然後合併。

操作二,由於線段樹不能夠很好的滿足我們的要求,所以我們可以選擇利用已經寫好了的操作一,對這個數進行二分處理,然後對於每乙個二分出的數字,進行操作一判定

操作三,暴力修改即可,對於每一棵包含這個位置的平衡樹,先將原數刪除,再插入新數

操作四&操作五 兩種做法

做法一:你可以選擇偷懶,先利用操作一,求出其排名,再利用操作二,求出排名-1(+1)的數字

做法二:對於區間中的每一棵平衡樹,對其進行求前驅(後繼)操作,然後再取最大(最小)值。

下面是本人為了偷懶寫得又醜,常數又大的線段樹套splay的**:

// luogu-judger-enable-o2

#include#include#define dir(p) (son[fa[p]][1]==p)

using namespace std;

const int maxn=4e6+10;

int inline read()

while(ch>='0'&&ch<='9')

return num*f;

}int n,m;

int siz[maxn],son[maxn][2],fa[maxn],num[maxn],tot[maxn],cnt;

void upd(int t)

void rot(int p)

struct splay

rot(p);

}if(g==0) root=p;

}void find(int x)

int pre(int x)

void insert(int x)

if(num[u]==x) ++tot[u];

else

splay(u,0);

}void remove(int x)

int rk(int x)

}}sp[1000001];

int a[1000010];

int ans=0;

void build(int l,int r,int t)

int ll,rr;

int tree_rank(int l,int r,int t,int x)

int tree_kth(int k)

return r;

}void change(int l,int r,int t,int p,int pre,int nu)

int tree_pre(int l,int r,int t,int x)

int tree_suc(int l,int r,int t,int x)

int main()

}return 0;

}

洛谷P3380 模板 二逼平衡樹(樹套樹)

查詢k在區間內的排名 查詢區間內排名為k的值 修改某一位值上的數值 查詢k在區間內的前驅 前驅定義為嚴格小於x,且最大的數,若不存在輸出 2147483647 查詢k在區間內的後繼 後繼定義為嚴格大於x,且最小的數,若不存在輸出2147483647 輸入格式 第一行兩個數 n,m 表示長度為n的有序...

洛谷P3380 模板 二逼平衡樹(樹套樹)

查詢k在區間內的排名 查詢區間內排名為k的值 修改某一位值上的數值 查詢k在區間內的前驅 前驅定義為嚴格小於x,且最大的數,若不存在輸出 2147483647 查詢k在區間內的後繼 後繼定義為嚴格大於x,且最小的數,若不存在輸出2147483647 輸入格式 第一行兩個數 n,m 表示長度為n的有序...

洛谷P3380 模板 二逼平衡樹(樹套樹)

查詢k在區間內的排名 查詢區間內排名為k的值 修改某一位值上的數值 查詢k在區間內的前驅 前驅定義為嚴格小於x,且最大的數,若不存在輸出 2147483647 查詢k在區間內的後繼 後繼定義為嚴格大於x,且最小的數,若不存在輸出2147483647 輸入格式 第一行兩個數 n,m 表示長度為n的有序...