splay模板
先贴一份不怎么完善的模板,等刷一些题目熟悉之后再来完善。代码参考自kuangbin及cxlove两位大神。
splay的基本功能
题目:维护一个数列,支持以下几种操作:
1. 插入:在当前数列第posi 个数字后面插入tot 个数字;若在数列首位插入,则posi 为0。
2. 删除:从当前数列第posi 个数字开始连续删除tot 个数字。
3. 修改:从当前数列第posi 个数字开始连续tot 个数字统一修改为c 。
4. 翻转:取出从当前数列第posi 个数字开始的tot 个数字,翻转后放入原来的位置。
5. 求和:计算从当前数列第posi 个数字开始连续tot 个数字的和并输出。
6. 求和最大子序列:求出当前数列中和最大的一段子序列,并输出最大和。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct splay_tree 2 { 3 int pre[N],size[N],vv[N]; 4 int ch[N][2]; 5 int root,n,tot,num,tot1; 6 int s[N],sta[N],key[N]; 7 void dfs(int x) 8 { 9 if(x) 10 { 11 dfs(ch[x][0]); 12 printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d s=%d vv=%d\n", 13 x,ch[x][0],ch[x][1],pre[x],size[x],key[x],s[x],vv[x]); 14 dfs(ch[x][1]); 15 } 16 } 17 void debug() 18 { 19 printf("root:%d\n",root); 20 dfs(root); 21 } 22 //以上用于debug*/ 23 void newnode(int &x,int v,int len,int fa)//新建一结点 24 { 25 x = ++tot; 26 ch[x][0]=ch[x][1] = 0; 27 pre[x] = fa; 28 size[x] = 1; 29 s[x] = len; 30 vv[x] = len; 31 key[x] = v; 32 po[f[v]] = x; 33 } 34 void pushup(int w)//由儿子更新其父亲 35 { 36 size[w] = size[ch[w][0]]+size[ch[w][1]]+1; 37 s[w] = s[ch[w][0]]+s[ch[w][1]]+vv[w]; 38 } 39 void rotate(int r,int kind)//旋转操作,根据kind进行左旋和右旋 40 { 41 int y = pre[r]; 42 ch[y][!kind] = ch[r][kind]; 43 pre[ch[r][kind]] = y; 44 if(pre[y]) 45 { 46 ch[pre[y]][ch[pre[y]][1]==y] = r; 47 } 48 pre[r] = pre[y]; 49 ch[r][kind] = y; 50 pre[y] = r; 51 pushup(y); 52 pushup(r); 53 } 54 void splay(int r,int goal)//将r结点旋至goal下 55 { 56 while(pre[r]!=goal) 57 { 58 if(pre[pre[r]]==goal) 59 { 60 rotate(r,ch[pre[r]][0]==r); 61 } 62 else 63 { 64 int y = pre[r]; 65 int kind = (ch[pre[y]][0]==y); 66 if(ch[y][kind]==r) 67 { 68 rotate(r,!kind); 69 rotate(r,kind); 70 } 71 else 72 { 73 rotate(y,kind); 74 rotate(r,kind); 75 } 76 } 77 } 78 pushup(r); 79 if(goal==0) root = r; 80 } 81 int get_k(int k)//得到第k个的结点 82 { 83 int r = root; 84 while(size[ch[r][0]]+1!=k) 85 { 86 if(size[ch[r][0]]>=k) 87 r = ch[r][0]; 88 else 89 { 90 k-=(size[ch[r][0]]+1);//根据左右结点的数量来确定第k个节点在哪里 91 r = ch[r][1]; 92 } 93 } 94 pushup(r); 95 return r; 96 } 97 void add(int v)//添加一个结点 位置自己修改 这里为第一个 98 { 99 splay(get_k(1),0); 100 splay(get_k(2),root); 101 int r = ch[root][1]; 102 newnode(ch[r][0],v,1,r); 103 pushup(r); 104 pushup(root); 105 } 106 void updelete(int k,int r)//删除第r个结点 107 { 108 splay(get_k(r),0); 109 splay(get_k(r+2),root); 110 //int ll = vv[key_value]; 111 key_value = 0; 112 /*if(ll>1) 113 newnode(key_value,k-1,ll-1,ch[root][1]);*/ 114 pushup(ch[root][1]); 115 pushup(root); 116 } 117 void update(int l,int r) //更新区间信息 118 { 119 120 } 121 int query(int l,int r)//询问l,r区间,将第l-1个结点旋自根,第r+1个结点旋自根的有儿子, 122 { 123 //则l-r就变成了根的右儿子的左儿子 124 splay(get_k(l),0); 125 splay(get_k(r+2),0); 126 return s[key_value]; 127 } 128 int find(int p,int x)//找到离散化后的第p个数 129 { 130 int l = ch[x][0]; 131 int r = ch[x][1]; 132 if(!l&&!r) 133 { 134 return key[x]-(vv[x]-p); 135 } 136 if(s[l]>=p) 137 return find(p,l); 138 else if(s[l]+vv[x]>=p) 139 return key[x]-(vv[x]-(p-s[l])); 140 else return find(p-s[l]-vv[x],r); 141 } 142 void build(int &x,int l,int r,int fa) 143 { 144 int m = (l+r)>>1; 145 if(l>r) return ; 146 newnode(x,va[m],len[m],fa); 147 build(ch[x][0],l,m-1,x); 148 build(ch[x][1],m+1,r,x); 149 pushup(x); 150 } 151 void init(int o) 152 { 153 size[0] = ch[0][0] = ch[0][1] = s[0] = key[0] = vv[0] = 0; 154 root = tot = 0; 155 newnode(root,0,0,0); 156 newnode(ch[root][1],0,0,root); 157 build(ch[ch[root][1]][0],1,o,ch[root][1]); 158 size[root] = 2; 159 pushup(ch[root][1]); 160 pushup(root); 161 } 162 }SP;