花了两天时间学了一下这三种数据结构。

总结 树上的修改与询问

 树专题(伸展树 / 树链剖分 / 动态树 学习笔记)

树专题(伸展树 / 树链剖分 / 动态树 学习笔记)

 

伸展树

  支持Spaly的平衡树。Splay操作可以让节点x旋转到树的根节点。

伸展树在区间插入,区间删除,区间翻转,区间旋转的问题中应用较多。

具体而言,我们可以以区间的下标为关键字构造伸展树。

在x与x+1中插入一段区间,我们可以通过Spaly操作完成,将x旋转至根节点,将x+1旋转至根节点的右节点,此时,x+1的左节点为空,插入该左节点即可。

删除 [ l, r ] 区间通过Splay后,直接令根节点的右节点的左节点为空即可。

翻转操作,可以类似线段树加入懒惰标记即可。

旋转区间,复杂一点可以三次翻转。优秀的见Claris代码。

其中,Spaly操作的均摊复杂度为O(log(n)).(treap的复杂度为期望复杂度O(log(n))) 

 

 1 const int N = 1e5+200;
 2 int a[N]; //输入数组
 3 int val[N], mn[N], tag[N], size[N], son[N][2], f[N], tot, root;
 4 bool rev[N];
 5 void rev1(int x) { //翻转以x为根的子树
 6     if(!x) return ;
 7     swap(son[x][0], son[x][1]);
 8     rev[x] ^= 1;
 9 }
10 void add1(int x,int p) { //以x为根的子树 +p
11     if(!x) return ;
12     val[x] += p;
13     mn[x] += p;
14     tag[x] += p;
15 }
16 void pb(int x){ 
17     if(rev[x]){
18         rev1(son[x][0]);
19         rev1(son[x][1]);
20         rev[x] = 0;
21     }
22     if(tag[x]){
23         add1(son[x][0], tag[x]);
24         add1(son[x][1], tag[x]);
25         tag[x] = 0;
26     }
27 }
28 void up(int x){
29     size[x] = 1, mn[x] = val[x];
30     if(son[x][0]){
31         size[x] += size[son[x][0]];
32         if(mn[x] > mn[son[x][0]]) mn[x] = mn[son[x][0]];
33     }
34     if(son[x][1]){
35         size[x] += size[son[x][1]];
36         if(mn[x] > mn[son[x][1]]) mn[x] = mn[son[x][1]];
37     }
38 }
39 void rotate(int x){ 
40     int y = f[x], w = son[y][1] == x;
41     son[y][w] = son[x][w^1];
42     if(son[x][w^1]) f[son[x][w^1]] = y;
43     if(f[y]){
44         int z = f[y];
45         if(son[z][0] == y) son[z][0] = x;
46         if(son[z][1] == y) son[z][1] = x;
47     }
48     f[x] = f[y]; son[x][w^1] = y; f[y] = x; up(y);
49 }
50 void splay(int x, int w){ //splay操作, 使得x的父节点为w, 注意包含端节点的情况
51     //一般通过x = kth(x)找到第x小的节点, w = kth(w)
52     int s = 1, i = x, y; a[1] = x;
53     while(f[i]) a[++s] = i = f[i];
54     while(s) pb(a[s--]);
55     while(f[x] != w){
56         y = f[x];
57         if(f[y] != w){
58             if((son[f[y]][0]==y)^(son[y][0]==x)) rotate(x);
59             else rotate(y);
60         }
61         rotate(x);
62     }
63     if(!w) root = x;
64     up(x);
65 }
66 int build(int l, int r, int fa){
67     int x = ++tot, mid = (l+r)>>1;
68     f[x] = fa; val[x] = a[mid];
69     if(l < mid) son[x][0] = build(l, mid-1, x);
70     if(r > mid) son[x][1] = build(mid+1, r, x);
71     up(x);
72     return x;
73 }
74 int kth(int k){
75     int x = root, tmp;
76     while(1){
77         pb(x);
78         tmp = size[son[x][0]]+1;
79         if(k == tmp) return x;
80         if(k < tmp) x = son[x][0];
81         else k -= tmp, x = son[x][1];
82     }
83 }
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-01-07
  • 2022-12-23
  • 2022-01-07
  • 2022-12-23
  • 2021-05-28
  • 2021-09-23
猜你喜欢
  • 2021-05-04
  • 2021-08-07
  • 2021-09-11
  • 2021-12-14
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案