这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
2020-2021:teams:legal_string:jxm2001:无旋treap [2020/07/08 12:34] jxm2001 |
2020-2021:teams:legal_string:jxm2001:无旋treap [2021/08/11 10:37] (当前版本) jxm2001 [集合维护版本] |
||
---|---|---|---|
行 12: | 行 12: | ||
$\text{fhq treap}$ 利用了 $\text{Treap}$ 的这条性质,实现了 $O(\log n)$ 的 $\text{split}$ 和 $\text{merge}$。 | $\text{fhq treap}$ 利用了 $\text{Treap}$ 的这条性质,实现了 $O(\log n)$ 的 $\text{split}$ 和 $\text{merge}$。 | ||
+ | |||
+ | $\text{split}$ 操作分两种,分别用于维护集合和序列。第一种 $\text{split}$ 操作根据权值 $v$ 将 $\text{fhq treap}$ 分成两部分。 | ||
+ | |||
+ | 每层 $\text{split}$ 都会到达结点 $k$ 的子节点,所以时间复杂度为原树的深度,根据 $\text{Treap}$ 的性质,深度为 $O(\log n)$。 | ||
<code cpp> | <code cpp> | ||
行 24: | 行 28: | ||
</code> | </code> | ||
- | $\text{split}$ 操作为根据权值 $v$ 将 $\text{fhq treap}$ 分成两部分。 | + | 另一种 $\text{split}$ 操作根据节点数 $\text{sz}$ 将 $\text{fhq treap}$ 分成两部分。 |
- | 每层 $\text{split}$ 都会到达结点 $k$ 的子节点,所以时间复杂度为原树的深度,根据 $\text{Treap}$ 的性质,深度为 $O(\log n)$。 | + | <code cpp> |
+ | void split(int k,int &k1,int &k2,int rk){ | ||
+ | if(!k) return k1=k2=0,void(); | ||
+ | pushdown(k); | ||
+ | if(node[node[k].ch[0]].sz+1<=rk){ | ||
+ | k1=k;split(node[k].ch[1],node[k1].ch[1],k2,rk-node[node[k].ch[0]].sz-1);pushup(k1); | ||
+ | }else{ | ||
+ | k2=k;split(node[k].ch[0],k1,node[k2].ch[0],rk);pushup(k2); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | $\text{merge}$ 操作根据优先级 $r$ 合并两棵树,要求保证前一棵树的结点权值均小于后一棵树的结点权值。 | ||
+ | |||
+ | 每层 $\text{merge}$ 都会到达结点 $k1$ 或 $k2$ 的子节点,所以时间复杂度为两树的深度和,根据 $\text{Treap}$ 的性质,深度为 $O(\log n)$。 | ||
<code cpp> | <code cpp> | ||
行 38: | 行 56: | ||
} | } | ||
</code> | </code> | ||
- | |||
- | $\text{merge}$ 操作为合并两棵树,要求保证前一棵树的结点权值均小于后一棵树的结点权值。 | ||
- | |||
- | 每层 $\text{merge}$ 都会到达结点 $k1$ 或 $k2$ 的子节点,所以时间复杂度为两树的深度和,根据 $\text{Treap}$ 的性质,深度为 $O(\log n)$。 | ||
有了 $\text{split}$ 和 $\text{merge}$ 操作,不难得到其他操作。 | 有了 $\text{split}$ 和 $\text{merge}$ 操作,不难得到其他操作。 | ||
行 47: | 行 61: | ||
===== 代码模板 ===== | ===== 代码模板 ===== | ||
- | [[https://www.luogu.com.cn/problem/P6136|洛谷p6136]] | + | ==== 集合维护版本 ==== |
+ | |||
+ | [[https://www.luogu.com.cn/problem/P3369|洛谷p3369]] | ||
<hidden 查看代码> | <hidden 查看代码> | ||
<code cpp> | <code cpp> | ||
- | #include <iostream> | + | const int MAXN=1e5+5; |
- | #include <cstdio> | + | namespace fhq_treap{ |
- | #include <cstdlib> | + | |
- | #include <algorithm> | + | |
- | #include <string> | + | |
- | #include <sstream> | + | |
- | #include <cstring> | + | |
- | #include <cctype> | + | |
- | #include <cmath> | + | |
- | #include <vector> | + | |
- | #include <set> | + | |
- | #include <map> | + | |
- | #include <stack> | + | |
- | #include <queue> | + | |
- | #include <ctime> | + | |
- | #include <cassert> | + | |
- | #define _for(i,a,b) for(int i=(a);i<(b);++i) | + | |
- | #define _rep(i,a,b) for(int i=(a);i<=(b);++i) | + | |
- | #define mem(a,b) memset(a,b,sizeof(a)) | + | |
- | using namespace std; | + | |
- | typedef long long LL; | + | |
- | inline int read_int(){ | + | |
- | int t=0;bool sign=false;char c=getchar(); | + | |
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | + | |
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | + | |
- | return sign?-t:t; | + | |
- | } | + | |
- | inline LL read_LL(){ | + | |
- | LL t=0;bool sign=false;char c=getchar(); | + | |
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | + | |
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | + | |
- | return sign?-t:t; | + | |
- | } | + | |
- | inline char get_char(){ | + | |
- | char c=getchar(); | + | |
- | while(c==' '||c=='\n'||c=='\r')c=getchar(); | + | |
- | return c; | + | |
- | } | + | |
- | inline void write(LL x){ | + | |
- | register char c[21],len=0; | + | |
- | if(!x)return putchar('0'),void(); | + | |
- | if(x<0)x=-x,putchar('-'); | + | |
- | while(x)c[++len]=x%10,x/=10; | + | |
- | while(len)putchar(c[len--]+48); | + | |
- | } | + | |
- | inline void space(LL x){write(x),putchar(' ');} | + | |
- | inline void enter(LL x){write(x),putchar('\n');} | + | |
- | const int MAXN=2e6+5; | + | |
- | struct fhq_treap{ | + | |
int root; | int root; | ||
struct Node{ | struct Node{ | ||
int val,r,sz,ch[2]; | int val,r,sz,ch[2]; | ||
}node[MAXN]; | }node[MAXN]; | ||
- | int pool[MAXN],top,tot; | + | int node_cnt; |
int New(int v){ | int New(int v){ | ||
- | int x=top?pool[top--]:++tot; | + | int k=++node_cnt; |
- | node[x].val=v,node[x].r=rand(),node[x].sz=1,node[x].ch[0]=node[x].ch[1]=0; | + | node[k].val=v; |
- | return x; | + | node[k].r=rand(),node[k].sz=1,node[k].ch[0]=node[k].ch[1]=0; |
+ | return k; | ||
+ | } | ||
+ | #define lch(k) node[node[k].ch[0]] | ||
+ | #define rch(k) node[node[k].ch[1]] | ||
+ | void push_up(int k){ | ||
+ | node[k].sz=lch(k).sz+rch(k).sz+1; | ||
} | } | ||
- | void Del(int x){if(x)pool[++top]=x;} | ||
- | void pushup(int k){node[k].sz=node[node[k].ch[0]].sz+node[node[k].ch[1]].sz+1;} | ||
void split(int k,int &k1,int &k2,int v){ | void split(int k,int &k1,int &k2,int v){ | ||
if(!k) return k1=k2=0,void(); | if(!k) return k1=k2=0,void(); | ||
if(node[k].val<=v){ | if(node[k].val<=v){ | ||
- | k1=k;split(node[k].ch[1],node[k1].ch[1],k2,v);pushup(k1); | + | k1=k; |
+ | split(node[k].ch[1],node[k1].ch[1],k2,v); | ||
+ | push_up(k1); | ||
}else{ | }else{ | ||
- | k2=k;split(node[k].ch[0],k1,node[k2].ch[0],v);pushup(k2); | + | k2=k; |
+ | split(node[k].ch[0],k1,node[k2].ch[0],v); | ||
+ | push_up(k2); | ||
} | } | ||
} | } | ||
行 123: | 行 100: | ||
if(!k1||!k2)return k=k1|k2,void(); | if(!k1||!k2)return k=k1|k2,void(); | ||
if(node[k1].r>node[k2].r){ | if(node[k1].r>node[k2].r){ | ||
- | k=k1;merge(node[k].ch[1],node[k1].ch[1],k2);pushup(k); | + | k=k1; |
+ | merge(node[k].ch[1],node[k1].ch[1],k2); | ||
+ | push_up(k); | ||
}else{ | }else{ | ||
- | k=k2;merge(node[k].ch[0],k1,node[k2].ch[0]);pushup(k); | + | k=k2; |
+ | merge(node[k].ch[0],k1,node[k2].ch[0]); | ||
+ | push_up(k); | ||
} | } | ||
} | } | ||
行 138: | 行 119: | ||
split(root,lef,rig,v); | split(root,lef,rig,v); | ||
split(lef,lef,mid,v-1); | split(lef,lef,mid,v-1); | ||
- | Del(mid); | ||
merge(mid,node[mid].ch[0],node[mid].ch[1]); | merge(mid,node[mid].ch[0],node[mid].ch[1]); | ||
merge(lef,lef,mid); | merge(lef,lef,mid); | ||
行 172: | 行 152: | ||
return kth(rk); | return kth(rk); | ||
} | } | ||
- | }tree; | + | #undef lch |
+ | #undef rch | ||
+ | }; | ||
int main() | int main() | ||
{ | { | ||
- | int n=read_int(),m=read_int(),opt,x,last=0,ans=0; | + | int n=read_int(),opt,x; |
while(n--){ | while(n--){ | ||
- | x=read_int(); | + | opt=read_int(),x=read_int(); |
- | tree.insert(x); | + | |
- | } | + | |
- | while(m--){ | + | |
- | opt=read_int(),x=read_int()^last; | + | |
switch(opt){ | switch(opt){ | ||
case 1: | case 1: | ||
- | tree.insert(x); | + | fhq_treap::insert(x); |
break; | break; | ||
case 2: | case 2: | ||
- | tree.erase(x); | + | fhq_treap::erase(x); |
break; | break; | ||
case 3: | case 3: | ||
- | ans^=(last=tree.rank(x)); | + | enter(fhq_treap::rank(x)); |
break; | break; | ||
case 4: | case 4: | ||
- | ans^=(last=tree.kth(x)); | + | enter(fhq_treap::kth(x)); |
break; | break; | ||
case 5: | case 5: | ||
- | ans^=(last=tree.pre(x)); | + | enter(fhq_treap::pre(x)); |
break; | break; | ||
case 6: | case 6: | ||
- | ans^=(last=tree.suf(x)); | + | enter(fhq_treap::suf(x)); |
break; | break; | ||
} | } | ||
} | } | ||
- | enter(ans); | ||
return 0; | return 0; | ||
} | } | ||
行 209: | 行 186: | ||
</hidden> | </hidden> | ||
+ | ==== 序列维护版本 ==== | ||
+ | [[https://www.luogu.com.cn/problem/P3391|洛谷p3391]] | ||
+ | |||
+ | <hidden 查看代码> | ||
+ | <code cpp> | ||
+ | const int MAXN=1e5+5; | ||
+ | namespace Treap{ | ||
+ | int root; | ||
+ | struct Node{ | ||
+ | int val; | ||
+ | int r,sz,ch[2]; | ||
+ | int flip; | ||
+ | }node[MAXN]; | ||
+ | int node_cnt; | ||
+ | int new_node(int v){ | ||
+ | int k=++node_cnt; | ||
+ | node[k].val=v; | ||
+ | node[k].r=rand(),node[k].sz=1,node[k].ch[0]=node[k].ch[1]=0; | ||
+ | node[k].flip=0; | ||
+ | return k; | ||
+ | } | ||
+ | #define lch(k) node[node[k].ch[0]] | ||
+ | #define rch(k) node[node[k].ch[1]] | ||
+ | void push_up(int k){ | ||
+ | node[k].sz=lch(k).sz+rch(k).sz+1; | ||
+ | } | ||
+ | void push_flip(int k){ | ||
+ | swap(node[k].ch[0],node[k].ch[1]); | ||
+ | node[k].flip^=1; | ||
+ | } | ||
+ | void push_down(int k){ | ||
+ | if(node[k].flip){ | ||
+ | push_flip(node[k].ch[0]); | ||
+ | push_flip(node[k].ch[1]); | ||
+ | node[k].flip=0; | ||
+ | } | ||
+ | } | ||
+ | void split(int k,int &k1,int &k2,int rk){ | ||
+ | if(!k)return k1=k2=0,void(); | ||
+ | push_down(k); | ||
+ | if(lch(k).sz+1<=rk){ | ||
+ | k1=k; | ||
+ | split(node[k].ch[1],node[k1].ch[1],k2,rk-lch(k).sz-1); | ||
+ | push_up(k1); | ||
+ | } | ||
+ | else{ | ||
+ | k2=k; | ||
+ | split(node[k].ch[0],k1,node[k2].ch[0],rk); | ||
+ | push_up(k2); | ||
+ | } | ||
+ | } | ||
+ | void merge(int &k,int k1,int k2){ | ||
+ | if(!k1||!k2)return k=k1|k2,void(); | ||
+ | if(node[k1].r>node[k2].r){ | ||
+ | push_down(k1); | ||
+ | k=k1; | ||
+ | merge(node[k].ch[1],node[k1].ch[1],k2); | ||
+ | push_up(k); | ||
+ | } | ||
+ | else{ | ||
+ | push_down(k2); | ||
+ | k=k2; | ||
+ | merge(node[k].ch[0],k1,node[k2].ch[0]); | ||
+ | push_up(k); | ||
+ | } | ||
+ | } | ||
+ | int Stack[MAXN]; | ||
+ | void build(int k){ | ||
+ | if(!k)return; | ||
+ | build(node[k].ch[0]); | ||
+ | build(node[k].ch[1]); | ||
+ | push_up(k); | ||
+ | } | ||
+ | void build(int *a,int n){ | ||
+ | int top=0; | ||
+ | Stack[top]=0; | ||
+ | node[0].r=0x7fffffff; | ||
+ | _for(i,0,n){ | ||
+ | int k=new_node(a[i]); | ||
+ | while(node[k].r>node[Stack[top]].r)top--; | ||
+ | node[k].ch[0]=node[Stack[top]].ch[1]; | ||
+ | node[Stack[top]].ch[1]=k; | ||
+ | Stack[++top]=k; | ||
+ | } | ||
+ | node[0].ch[0]=node[0].ch[1]=0; | ||
+ | root=Stack[1]; | ||
+ | build(root); | ||
+ | } | ||
+ | void flip(int L,int R){ | ||
+ | int lef,mid,rig; | ||
+ | split(root,lef,rig,R); | ||
+ | split(lef,lef,mid,L-1); | ||
+ | push_flip(mid); | ||
+ | merge(lef,lef,mid); | ||
+ | merge(root,lef,rig); | ||
+ | } | ||
+ | void dfs(int k,int *a){ | ||
+ | if(!k)return; | ||
+ | push_down(k); | ||
+ | dfs(node[k].ch[0],a); | ||
+ | a[lch(k).sz]=node[k].val; | ||
+ | a+=lch(k).sz+1; | ||
+ | dfs(node[k].ch[1],a); | ||
+ | } | ||
+ | }; | ||
+ | int a[MAXN]; | ||
+ | int main() | ||
+ | { | ||
+ | int n=read_int(),m=read_int(); | ||
+ | _for(i,0,n)a[i]=i+1; | ||
+ | Treap::build(a,n); | ||
+ | while(m--){ | ||
+ | int lef=read_int(),rig=read_int(); | ||
+ | Treap::flip(lef,rig); | ||
+ | } | ||
+ | Treap::dfs(Treap::root,a); | ||
+ | _for(i,0,n)space(a[i]); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||