话说天下大事,就像fhq treap —— 分久必合,合久必分
简单讲一讲。非旋treap主要依靠分裂和合并来实现操作。(递归,不维护fa)
合并的前提是两棵树的权值满足一边的最大的比另一边最小的还小。因此时合并时只需要维护键值的堆性质即可。这样每一次比较根节点,如果x比y小那么y直接接到x的右子树即可(需要满足权值的平衡树性质);否则的话只需要反过来,把x接到y的左子树上。merge函数返回的值应当是合并完后的根节点。
分裂分为两种,排名和权值。然而我认为它们本质上是一样的。对于权值的分裂,对于每一个子树的根节点,若根节点比给定值a小,那么此节点及左子树一定比a小,归入x。否则此节点及右子树归入y。然后再递归操作还没有分类的那一个子树就好了。代码实现中的引用用的非常巧妙。可以把这里的引用理解为是需要修改的东西,利用递归的过程对其作出修改。
合并看键值,分裂看权值。
$Merge$
int merge(int u, int v){ if(!u||!v) return u|v; if(key[u] < key[v]){ ch[u][1] = merge(ch[u][1], v); pushup(u); return u; } else{ ch[v][0] = merge(u, ch[v][0]); pushup(v); return v; } }
$Split$
void split_a(int u, int a, int& x, int& y){ if(!u){ x = y = 0; return; } if(val[u] <= a){ x = u; split_a(ch[u][1], a, ch[u][1], y); } else{ y = u; split_a(ch[u][0], a, x, ch[u][0]); } pushup(u); } void split_k(int u, int k, int& x, int& y){ if(!u){ x = y = 0; return; } if(size[ch[u][0]]+cnt[u] <= k){ x = u; split_k(ch[u][1], k-size[ch[u][0]]-cnt[u], ch[u][1], y); } else{ y = u; split_k(ch[u][0], k, x, ch[u][0]); } pushup(u); }
有了这两个操作,其他操作yy一下即可,非常简便。
当然,在查询k大排名或前驱后继时,完全可以用普通平衡树(如splay)的做法。因为它满足平衡树的性质。也就是傻乎乎的去logn的从根节点往下走。那么既然我们有了split,查询最大最小值应该很方便了。要尽量让代码精简啊!
My Code:
/*By DennyQi 2018*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #include <ctime> #include <cstdlib> using namespace std; typedef long long ll; const int MAXN = 100010; const int INF = 0x3f3f3f3f; inline int Max(const int a, const int b){ return (a > b) ? a : b; } inline int Min(const int a, const int b){ return (a < b) ? a : b; } inline int read(){ int x = 0; int w = 1; register char c = getchar(); for(; c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘); c = getchar()); if(c == ‘-‘) w = -1, c = getchar(); for(; c >= ‘0‘ && c <= ‘9‘; c = getchar()) x = (x<<3) + (x<<1) + c - ‘0‘; return x * w; } int N,opt,x,num_node,RooT; int ch[MAXN][2],val[MAXN],key[MAXN],size[MAXN],cnt[MAXN]; inline void pushup(int x){ size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; } inline void clear(int x){ size[x]=cnt[x]=val[x]=key[x]=ch[x][0]=ch[x][1]=0; } int merge(int u, int v){ if(!u||!v) return u|v; if(key[u] < key[v]){ ch[u][1] = merge(ch[u][1], v); pushup(u); return u; } else{ ch[v][0] = merge(u, ch[v][0]); pushup(v); return v; } } void split_a(int u, int a, int& x, int& y){ if(!u){ x = y = 0; return; } if(val[u] <= a){ x = u; split_a(ch[u][1], a, ch[u][1], y); } else{ y = u; split_a(ch[u][0], a, x, ch[u][0]); } pushup(u); } void split_k(int u, int k, int& x, int& y){ if(!u){ x = y = 0; return; } if(size[ch[u][0]]+cnt[u] <= k){ x = u; split_k(ch[u][1], k-size[ch[u][0]]-cnt[u], ch[u][1], y); } else{ y = u; split_k(ch[u][0], k, x, ch[u][0]); } pushup(u); } inline void Insert(int v){//以v进行分裂,插入后合并。 val[++num_node]= v; key[num_node] = rand(); size[num_node] = cnt[num_node] = 1; int a,b; split_a(RooT, v, a, b); RooT = merge(merge(a,num_node), b); } inline void Delete(int v){//以v进行分裂,删除后合并。 int a,b,c,d; split_a(RooT, v, a, b); split_k(a, size[a]-1, c, d); if(cnt[d] > 1) --cnt[d]; else clear(d); RooT = merge(c, b); } inline int Rank(int v){//以v-1进行分裂,看左侧树的size int a,b,ans; split_a(RooT, v-1, a, b); ans = size[a]+1; RooT = merge(a, b); return ans; } inline int Kth(int k){//以k进行分裂,依旧看左侧的size,但注意再分裂一次取出比k小的 int a,b,c,d,ans; split_k(RooT, k, a, b); split_k(a,size[a]-1,c,d); ans = val[d]; RooT = merge(merge(c,d),b); return ans; } inline int Pre(int v){//与kth同理 int a,b,c,d,ans; split_a(RooT, v-1, a, b); split_k(a,size[a]-1,c,d); ans = val[d]; RooT = merge(merge(c,d),b); return ans; } inline int Nxt(int v){ int a,b,c,d,ans; split_a(RooT, v, a, b); split_k(b, 1, c, d); ans = val[c]; RooT = merge(a,merge(c,d)); return ans; } void PrintTree(int u){ if(ch[u][0]) PrintTree(ch[u][0]); printf("%d ",val[u]); if(ch[u][1]) PrintTree(ch[u][1]); } int main(){ // freopen(".in","r",stdin); srand((unsigned)time(NULL)); N = read(); while(N--){ opt = read(), x = read(); if(opt == 1) Insert(x); if(opt == 2) Delete(x); if(opt == 3) printf("%d\n", Rank(x)); if(opt == 4) printf("%d\n", Kth(x)); if(opt == 5) printf("%d\n", Pre(x)); if(opt == 6) printf("%d\n", Nxt(x)); } return 0; }
原文:https://www.cnblogs.com/qixingzhi/p/10010047.html