P6136 【模板】普通平衡树(数据加强版) 非旋转treap算法指针版
作者:互联网
//非旋转的Treap树 #include<bits/stdc++.h> using namespace std; const int INF=0x7fffffff; struct Node *nil; // 自定义的空指针,防止翻车(RE) struct Node { Node *ch[2]; // 结点的左右孩子。为什么不分开写成lc,rc呢?往后就知道了 int v, s, c; // v表示该结点的值,s表示以该结点为根的子树大小,c表示权值v的结点数量(合并了相同权值的结点),即v的副本数量 int r; // Treap专有的随机数,是大根堆的关键字 void maintain() { // 维护当前结点的信息 s = ch[0]->s + ch[1]->s + c; } Node(int v) : v(v), c(1), s(1), r(rand()) { ch[0] = ch[1] = nil; } // 新建结点 } *root; void init() { srand(0); // 随机数初始化 nil = new Node(0); // 空指针初始化 root = nil->ch[0] = nil->ch[1] = nil; // 左右孩子指向自身 nil->s = nil->c = 0; // 防止空指针影响后面的操作 } void split(Node *o, int v, Node* &l, Node* &r) { if (o == nil) { l = r = nil; return; } // 到了空结点两边附上空后结束 if (o->v < v) { l = o; split(o->ch[1], v, l->ch[1], r); l->maintain(); } // 第一种情况。注意分裂后要及时维护信息 else { r = o; split(o->ch[0], v, l, r->ch[0]); r->maintain(); } // 第二种情况。同上 } Node* merge(Node *a, Node *b) { if (a == nil) return b; // 如果a空返回b if (b == nil) return a; // 如果b空返回a if (a->r > b->r) { a->ch[1] = merge(a->ch[1], b); a->maintain(); return a; } // 比较两者的随机关键字,大的先合并 else { b->ch[0] = merge(a, b->ch[0]); b->maintain(); return b; } } void insert(Node* &rt, int v) { Node *l, *r; split(rt, v, l, r); rt = merge(merge(l, new Node(v)), r); } void remove(Node* &rt, int v) { Node *l, *mid, *r; split(rt, v, l, r); split(r, v+1, mid, r); rt = merge(merge(l, merge(mid->ch[0], mid->ch[1])), r); delete mid; } //v的排名 int get_rank(Node* o, int v) { /* 10 /\ 4 \ 10 /\ 7 /\ .. 10 有错 if (v < o->v) return get_rank(o->ch[0], v); // v在左子树中 if (o->ch[0]&&o->ch[0]->v==v) return get_rank(o->ch[0],v); if (o->v== v) return o->ch[0]->s + 1; // 找到v return get_rank(o->ch[1], v) + o->ch[0]->s + o->c; // v在右子树中,此时要将左子树中的所有元素以及根的元素数统计起来 */ /* int ans=0; while(o!=nil) { if (o->v>=v) { o=o->ch[0]; } else { ans+=o->ch[0]->s+1; o=o->ch[1]; } } return ans+1; */ if (o==nil) return 1; if (o->v>=v) return get_rank(o->ch[0],v); else return o->ch[0]->s+1+get_rank(o->ch[1],v); } //第k小数 int get_val(Node* o, int k) { if (k <= o->ch[0]->s) return get_val(o->ch[0], k); // 排名为k的数在左子树中 else if (k == o->ch[0]->s + o->c) return o->v; // 为o else return get_val(o->ch[1], k - o->ch[0]->s - o->c); // 在右子树中 } int get_pre(Node *o, int v) { // 查前驱 if (o == nil) return -INF; // 找到空结点返回无穷小目的是不干扰其它解 if (o->v >= v) return get_pre(o->ch[0], v); // v大于当前结点o的值,向左走找小一点的值 return max(o->v, get_pre(o->ch[1], v)); // 否则向右走找更大的值并与当前值比较 /* 有点慢 if (o == nil) return -INF; // 找到空结点返回无穷小目的是不干扰其它解 return get_val(o,get_rank(o,v)-1); */ } int get_next(Node *o, int v) { // 查后继,与上面完全相反 /* if (o == nil) return INF; if (o->v <= v) return get_next(o->ch[1], v); return min(o->v, get_next(o->ch[0], v)); */ return get_val(o,get_rank(o,v+1));//有点慢 } int main() { int n,m,op,x,last=0,ans=0; init(); scanf("%d %d",&n,&m); while(n--) { scanf("%d",&x); insert(root,x); } while(m--) { scanf("%d %d",&op,&x); x=last^x; if (op==1) insert(root,x); else if(op==2) remove(root,x); else if(op==3) { last=get_rank(root,x); ans^=last; } else if(op==4) { last=get_val(root,x); ans^=last; } else if(op==5) { last=get_pre(root,x); ans^=last; } else if(op==6) { last=get_next(root,x); ans^=last; } } cout<<ans<<endl; }
标签:Node,ch,return,加强版,nil,get,int,treap,P6136 来源: https://www.cnblogs.com/smghj/p/16063778.html