一、斜堆
斜堆是一种可以合并的堆
节点信息:
struct Node { int v; Node *ch[2]; };
主要利用merge函数
Node *merge(Node *x, Node *y) { if(!x) return y; if(!y) return x; if(x->v < y->v) swap(x, y); x->ch[1] = merge(x->ch[1], y); return swap(x->ch[0], x->ch[1]), x; }
左偏树需要维护一个额外的信息,而斜堆每次强制swap(ch[0], ch[1]),以达到均摊$O(\log{n})$的效果
利用merge函数可以很容易地实现插入和删除
void ins(Node*& o, int x) { o = merge(o, new Node(x)); } void del(Node*& o) { o = merge(o->ch[0], o->ch[1]); }
另外地,堆相对与平衡树来说无法删除一个元素,但是如果能够定位到这个指针就可以删除这个元素了,方法是存储父亲(merge里要维护一下fa)
删除一个元素时可以这样
void del(Node*& o) { Node* p = o->fa; Node* r = merge(o->ch[0], o->ch[1]); r->fa = p; p->ch[p->ch[1] == o] = r; }
当然,和其他树形结构一样,堆上也是可以维护tag的
加入maintain()函数和down()函数后就可以轻松实现这些功能,方法和其他树形结构类似
需要注意的是删除时要像自底向上的splay一样把从这个点到根的路径上的点都down()一遍,再调用del()函数
另外,由于堆高度是均摊$O(\log{n})$的,所以在处理集合信息时不需要额外的并查集,只需要每次暴力往上找到根来比较就能够做到$O(\log{n})$的复杂度了。
!!!
!!!我现在收回 高度并不是均摊$O(\log{n})$高度是可以很大的 是会被卡的!!!!
举一例带标记的题
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<string> 7 8 using namespace std; 9 10 void setIO(const string& a) { 11 freopen((a+".in").c_str(), "r", stdin); 12 freopen((a+".out").c_str(), "w", stdout); 13 } 14 15 typedef long long ll; 16 const int N = 300000 + 10; 17 18 struct Node* pis; 19 struct Node { 20 ll v, a, m; 21 int id, fk, tag; 22 Node* ch[2]; 23 24 void add_tag(ll add, ll mul, int ft) { 25 if(this) { 26 fk += ft; 27 tag += ft; 28 (v *= mul) += add; 29 m *= mul; 30 (a *= mul) += add; 31 } 32 } 33 34 void down() { 35 ch[0]->add_tag(a, m, tag); 36 ch[1]->add_tag(a, m, tag); 37 tag = a = 0, m = 1; 38 } 39 40 void *operator new(size_t) { 41 return pis++; 42 } 43 44 Node(ll v = 0, int id = 0) : v(v), id(id) { 45 ch[0] = ch[1] = 0; 46 a = 0; 47 m = 1; 48 fk = tag = 0; 49 } 50 }pool[N], *root[N]; 51 52 Node *merge(Node *l, Node *r) { 53 if(!l || !r) return l ? l : r; 54 if(l->v > r->v) swap(l, r); 55 l->down(); 56 l->ch[1] = merge(l->ch[1], r); 57 return swap(l->ch[0], l->ch[1]), l; 58 } 59 60 ll h[N], f[N], a[N], v[N]; 61 int ansn[N], ansm[N]; 62 63 template<typename Q> void gt(Q& x) { 64 static char c; 65 static bool f; 66 for(f = 0; c = getchar(), !isdigit(c); ) if(c == '-') f = 1; 67 for(x = 0; isdigit(c); c = getchar()) x = x * 10 + c - '0'; 68 if(f) x = -x; 69 } 70 71 void ddd(Node* o) { 72 if(!o) return; 73 o->down(); 74 ddd(o->ch[0]); 75 ddd(o->ch[1]); 76 } 77 78 int main() { 79 #ifdef DEBUG 80 freopen("in.txt", "r", stdin); 81 freopen("out.txt", "w", stdout); 82 #endif 83 84 pis = pool; 85 int n, m; 86 gt(n), gt(m); 87 for(int i = 1; i <= n; i++) { 88 gt(h[i]); 89 } 90 for(int i = 2; i <= n; i++) { 91 gt(f[i]), gt(a[i]), gt(v[i]); 92 } 93 for(int i = 1; i <= m; i++) { 94 ll s, c; 95 gt(s), gt(c); 96 root[c] = merge(root[c], new Node(s, i)); 97 } 98 99 for(int i = n; i >= 1; i--) { 100 Node*& r = root[i]; 101 while(r && r->v < h[i]) { 102 ansn[i]++; 103 r->down(); 104 r = merge(r->ch[0], r->ch[1]); 105 } 106 ll add = 0, mul = 1; 107 if(a[i] == 0) add += v[i]; 108 else mul *= v[i]; 109 r->add_tag(add, mul, 1); 110 root[f[i]] = merge(root[f[i]], r); 111 } 112 113 for(int i = 1; i <= n; i++) { 114 printf("%d\n", ansn[i]); 115 } 116 ddd(root[0]); 117 for(int i = 0; i < m; i++) { 118 ansm[pool[i].id] = pool[i].fk; 119 } 120 for(int i = 1; i <= m; i++) { 121 printf("%d\n", ansm[i]); 122 } 123 124 return 0; 125 }