先贴一份不怎么完善的模板,等刷一些题目熟悉之后再来完善。代码参考自kuangbin及cxlove两位大神。
splay的基本功能
题目:维护一个数列,支持以下几种操作:
1. 插入:在当前数列第posi 个数字后面插入tot 个数字;若在数列首位插入,则posi 为0。
2. 删除:从当前数列第posi 个数字开始连续删除tot 个数字。
3. 修改:从当前数列第posi 个数字开始连续tot 个数字统一修改为c 。
4. 翻转:取出从当前数列第posi 个数字开始的tot 个数字,翻转后放入原来的位置。
5. 求和:计算从当前数列第posi 个数字开始连续tot 个数字的和并输出。
6. 求和最大子序列:求出当前数列中和最大的一段子序列,并输出最大和。
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 using namespace std; 11 #define N 200010 12 #define LL __int64 13 #define INF 0xfffffff 14 #define key_value ch[ch[root][1]][0] 15 const double eps = 1e-8; 16 const double pi = acos(-1.0); 17 const double inf = ~0u>>2; 18 int pre[N],s[N],size[N]; 19 int ch[N][2],a[N],val[N],key[N]; 20 int root,n,tot; 21 void dfs(int x) 22 { 23 if(x) 24 { 25 dfs(ch[x][0]); 26 printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d add=%2d sum=%I64d\n", 27 x,ch[x][0],ch[x][1],pre[x],size[x],key[x],add[x],s[x]); 28 dfs(ch[x][1]); 29 } 30 } 31 void debug() 32 { 33 printf("root:%d\n",root); 34 dfs(root); 35 } 36 //以上用于debug 37 void newnode(int &x,int k,int fa)//新建一结点 38 { 39 x = ++tot; 40 ch[x][0]=ch[x][1] = 0; 41 pre[x] = fa; 42 size[x] = 1; 43 s[x] = k; 44 val[x] = k; 45 } 46 void pushup(int w)//由儿子更新其父亲 47 { 48 size[w] = size[ch[w][0]]+size[ch[w][1]]+1; 49 s[w] = max(max(s[ch[w][0]],s[ch[w][1]]),val[w]); 50 } 51 void rotate(int r,int kind)//旋转操作,根据kind进行左旋和右旋 52 { 53 int y = pre[r]; 54 ch[y][!kind] = ch[r][kind]; 55 pre[ch[r][kind]] = y; 56 if(pre[y]) 57 { 58 ch[pre[y]][ch[pre[y]][1]==y] = r; 59 } 60 pre[r] = pre[y]; 61 ch[r][kind] = y; 62 pre[y] = r; 63 pushup(y); 64 } 65 void splay(int r,int goal)//将r结点旋至goal下 66 { 67 while(pre[r]!=goal) 68 { 69 if(pre[pre[r]]==goal) 70 { 71 rotate(r,ch[pre[r]][0]==r); 72 } 73 else 74 { 75 int y = pre[r]; 76 int kind = (ch[pre[y]][0]==y); 77 if(ch[y][kind]==r) 78 { 79 rotate(r,!kind); 80 rotate(r,kind); 81 } 82 else 83 { 84 rotate(y,kind); 85 rotate(r,kind); 86 } 87 } 88 } 89 pushup(r); 90 if(goal==0) root = r; 91 } 92 int get_k(int k)//得到第k个的结点 93 { 94 int r = root; 95 while(size[ch[r][0]]!=k) 96 { 97 if(size[ch[r][0]]>k) 98 r = ch[r][0]; 99 else 100 { 101 k-=(size[ch[r][0]]+1);//根据左右结点的数量来确定第k个节点在哪里 102 r = ch[r][1]; 103 } 104 } 105 return r; 106 } 107 int query(int l,int r)//询问l,r区间,将第l-1个结点旋自根,第r+1个结点旋自根的有儿子, 108 { //则l-r就变成了根的右儿子的左儿子 109 splay(get_k(l-1),0); 110 splay(get_k(r+1),root); 111 return s[key_value]; 112 } 113 void update(int l,int r,int k)//区间更新,类似于询问 114 { 115 splay(get_k(l-1),0); 116 splay(get_k(r+1),root); 117 val[key_value] = k; 118 s[key_value] = k; 119 pushup(ch[root][1]); 120 pushup(root); 121 } 122 void update(int l,int r,int k)//单点更新,将所求点旋至根 123 { 124 int kk = get_k(l); 125 val[kk] = k; 126 splay(kk,0); 127 } 128 void build(int &w,int l,int r,int fa)//递归建树 129 { 130 if(l>r) return ; 131 int m = (l+r)>>1; 132 newnode(w,a[m],fa); 133 build(ch[w][0],l,m-1,w); 134 build(ch[w][1],m+1,r,w); 135 pushup(w); 136 } 137 void init()//初始化操作,增加一个最小和最大值结点,防止越界 138 { 139 int i; 140 for(i = 0 ;i < n ;i++) 141 scanf("%d",&a[i]); 142 ch[0][0] = ch[0][1] = pre[0] = size[0] = s[0] = 0; 143 root = tot =0; 144 newnode(root,-1,0); 145 newnode(ch[root][1],-1,root); 146 size[root] = 2; 147 build(key_value,0,n-1,ch[root][1]); 148 pushup(ch[root][1]); 149 pushup(root); 150 }
时间: 2024-12-27 08:50:05