Splay_Tree 模板(区间修改,旋转操作)
Posted chenhuan001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Splay_Tree 模板(区间修改,旋转操作)相关的知识,希望对你有一定的参考价值。
1.旋转操作
#define MAXN 100100 bool Add[MAXN];//延迟标记 struct Splay_Tree { int cnt, rt;//cnt为节点数,rt == root struct Tree{ int key;//关键字 int num, size;//num是这个节点有多少重复,size是以这个节点为根的子树大小。 int fa, son[2]; }T[MAXN]; inline void init() { cnt = 0;//初始化超级根节点(标记为0的节点) T[0].size = 0; rt = 0; memset(Add,0,sizeof(Add));//开始初始化0 } inline void PushUp(int x) { T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num; } inline void PushDown(int x) { //翻转操作,这一步最为关键 if(Add[x]) { swap(T[x].son[0],T[x].son[1]); Add[T[x].son[0]] ^= 1; Add[T[x].son[1]] ^= 1; Add[x] = 0; } } inline int Newnode(int key, int fa) //新建一个节点并返回 { ++cnt; T[cnt].key=key; T[cnt].num=T[cnt].size=1; T[cnt].fa=fa; T[cnt].son[0]=T[cnt].son[1]=0; return cnt; } inline void Rotate(int x, int p) //0左旋 1右旋 { int y=T[x].fa; PushDown(y);//你是说这个有问题。 PushDown(x); T[y].son[!p]=T[x].son[p]; T[T[x].son[p]].fa=y; T[x].fa=T[y].fa; if(T[x].fa) T[T[x].fa].son[T[T[x].fa].son[1] == y]=x; T[x].son[p]=y; T[y].fa=x; PushUp(y); PushUp(x); } void Splay(int x, int To) //将x节点移动到To的子节点中 { while(T[x].fa != To) { if(T[T[x].fa].fa == To) { //在这里面得 PushDown(T[x].fa); PushDown(x); Rotate(x, T[T[x].fa].son[0] == x); } else { int y=T[x].fa, z=T[y].fa; PushDown(z); PushDown(y); PushDown(x); int p=(T[z].son[0] == y); if(T[y].son[p] == x) Rotate(x, !p), Rotate(x, p); //之字旋 else Rotate(y, p), Rotate(x, p); //一字旋 } } if(To == 0) rt=x; } int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中 { if(!rt || p > T[rt].size) return 0; int x=rt; while(x) { PushDown(x); if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num) break; if(p > T[T[x].son[0]].size+T[x].num) { p-=T[T[x].son[0]].size+T[x].num; x=T[x].son[1]; } else x=T[x].son[0]; } Splay(x, 0); return x; } int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处 { if(!rt) return 0; int x=rt; while(x) { PushDown(x); if(T[x].key == key) break; x=T[x].son[key > T[x].key]; } if(x) Splay(x, 0); return x; } int Prev() //返回根节点的前驱 非重点 { if(!rt || !T[rt].son[0]) return 0; int x=T[rt].son[0]; PushDown(x); while(T[x].son[1]) { x=T[x].son[1]; PushDown(x); } Splay(x, 0); return x; } int next() //返回根结点的后继 非重点 { if(!rt || !T[rt].son[1]) return 0; int x=T[rt].son[1]; PushDown(x); while(T[x].son[0]) { x=T[x].son[0]; PushDown(x); } Splay(x, 0); return x; } void Insert(int key) //插入key值 { if(!rt) rt=Newnode(key, 0); else { int x=rt, y=0; while(x) { PushDown(x); y=x; if(T[x].key == key) { T[x].num++; T[x].size++; break; } T[x].size++;//既然一定调整 x=T[x].son[key > T[x].key]; } if(!x) x = T[y].son[key > T[y].key] = Newnode(key, y); Splay(x, 0); } } void Delete()//直接改成删除根节点 { if(rt == 0) return ;//已经没有节点了 if(T[rt].num > 1) { T[rt].num --; T[rt].size --; return ; } if(T[rt].son[0] == 0) { rt = T[rt].son[1]; T[rt].fa = 0; } else { int preid = T[rt].son[0]; PushDown(preid); while(T[preid].son[1]) { preid = T[preid].son[1]; PushDown(preid); } Splay(preid, rt); T[preid].son[1] = T[rt].son[1]; T[ T[rt].son[1] ].fa = preid; rt = preid; T[rt].fa = 0; PushUp(rt); } } // int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为< // { // //我没有写PUSH_UP 和 PUSH_DOWN // if(!rt) return 0; // int x=rt, ret=0, y=0; // while(x) // { // y=x; // if(T[x].key <= key) // { // ret += T[T[x].son[0]].size + T[x].num; // x=T[x].son[1]; // } // else // x=T[x].son[0]; // } // Splay(y, 0); // return ret; // } // 这个删除太丑了 // void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r // { // if(!Find(l)) Insert(l);// 你这样写真的好吗? 泥煤 // int p=Prev(); // if(!Find(r)) Insert(r); // int q=next(); // if(!p && !q) // { // rt=0; // return; // } // if(!p) // { // T[rt].son[0]=0; // PushUp(rt); // return; // } // if(!q) // { // Splay(p, 0); // T[rt].son[1]=0; // PushUp(rt); // return; // } // Splay(p, q); // T[p].son[1]=0; // PushUp(p); // PushUp(q); // } void display(int x) { if(x==0) return ; PushDown(x); display(T[x].son[0]); printf("%d ",T[x].key); display(T[x].son[1]); } }spt; // //int main() { // //SPT 独特的旋转操作! // int n; // while(scanf("%d",&n) && n) // { // spt.init(); // for(int i=1;i<=n;i++) // { // int tmp; // scanf("%d",&tmp); // g[i].key = tmp; // g[i].id = i; // spt.Insert(i); // } // // sort(g+1,g+1+n,cmp); // for(int i=1;i<=n;i++)//开始旋转 // { // //step one 将当前最小的点,移动到树根处 // spt.Splay(g[i].id, 0); // // //step two 将整个左子树旋转 // int sonid = spt.T[g[i].id].son[0]; // printf("%d",spt.T[sonid].size+i); // if(i!=n) printf(" "); // if(sonid != 0) // { // Add[sonid] ^= 1;//修改区间 // } // spt.Delete(); // // //每次操作之后,都把结果打印一遍 // //spt.display(spt.rt); // //printf("\n"); // } // printf("\n"); // } // return 0; //}
2.成段更#define MAXN 200100
long long Add[MAXN];//延迟标记 struct Splay_Tree { int cnt, rt;//cnt为节点数,rt == root struct Tree{ long long K; long long sumk; int key;//关键字 int num, size;//num是这个节点有多少重复,size是以这个节点为根的子树大小。 int fa, son[2]; }T[MAXN]; inline void init() { cnt = 0;//初始化超级根节点(标记为0的节点) T[0].size = 0; T[0].sumk = 0; T[0].K = 0; rt = 0; memset(Add,0,sizeof(Add)); } inline void PushUp(int x) { T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num; T[x].sumk=T[T[x].son[0]].sumk+T[T[x].son[1]].sumk+T[x].K; } inline void PushDown(int x) { if(Add[x]) { if(T[x].son[0])// { T[T[x].son[0]].K += Add[x]; T[T[x].son[0]].sumk += T[T[x].son[0]].size*Add[x]; Add[T[x].son[0]]+=Add[x]; } if(T[x].son[1]) { T[T[x].son[1]].K+=Add[x]; T[T[x].son[1]].sumk += T[T[x].son[1]].size*Add[x]; Add[T[x].son[1]]+=Add[x]; } Add[x]=0;//不管子节点有没有,这层一定往下推,没有子节点相当于标记无效。 } } inline int Newnode(int key, int fa,int K) //新建一个节点并返回 { ++cnt; T[cnt].K = T[cnt].sumk = K; T[cnt].key=key; T[cnt].num=T[cnt].size=1; T[cnt].fa=fa; T[cnt].son[0]=T[cnt].son[1]=0; return cnt; } inline void Rotate(int x, int p) //0左旋 1右旋 { int y=T[x].fa; PushDown(y);//这里是不是必须的,我感觉从小往上不需要往上推 PushDown(x); T[y].son[!p]=T[x].son[p]; T[T[x].son[p]].fa=y; T[x].fa=T[y].fa; if(T[x].fa) T[T[x].fa].son[T[T[x].fa].son[1] == y]=x; T[x].son[p]=y; T[y].fa=x; PushUp(y); PushUp(x); } void Splay(int x, int To) //将x节点移动到To的子节点中 { while(T[x].fa != To) { if(T[T[x].fa].fa == To) Rotate(x, T[T[x].fa].son[0] == x); else { int y=T[x].fa, z=T[y].fa; int p=(T[z].son[0] == y); if(T[y].son[p] == x) Rotate(x, !p), Rotate(x, p); //之字旋 else Rotate(y, p), Rotate(x, p); //一字旋 } } if(To == 0) rt=x; } int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中 { if(!rt || p > T[rt].size) return 0; int x=rt; while(x) { PushDown(x); if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num) break; if(p > T[T[x].son[0]].size+T[x].num) { p-=T[T[x].son[0]].size+T[x].num; x=T[x].son[1]; } else x=T[x].son[0]; } Splay(x, 0); return x; } int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处 { if(!rt) return 0; int x=rt; while(x) { PushDown(x); if(T[x].key == key) break; x=T[x].son[key > T[x].key]; } if(x) Splay(x, 0); return x; } int Prev() //返回根节点的前驱 非重点 { if(!rt || !T[rt].son[0]) return 0; int x=T[rt].son[0]; while(T[x].son[1]) { PushDown(x); x=T[x].son[1]; } Splay(x, 0); return x; } int next() //返回根结点的后继 非重点 { if(!rt || !T[rt].son[1]) return 0; int x=T[rt].son[1]; while(T[x].son[0]) { PushDown(x); x=T[x].son[0]; } Splay(x, 0); return x; } void Insert(int key,int K) //插入key值 { if(!rt) rt=Newnode(key, 0, K); else { int x=rt, y=0; while(x) { PushDown(x); y=x; if(T[x].key == key) { T[x].num++; T[x].size++; break; } T[x].size++;//既然一定调整 x=T[x].son[key > T[x].key]; } if(!x) x = T[y].son[key > T[y].key] = Newnode(key, y, K); Splay(x, 0); } }
// void Delete()//直接改成删除根节点
// {
// if(rt == 0) return ;//已经没有节点了
// if(T[rt].num > 1)
// {
// T[rt].num --;
// T[rt].size --;
// return ;
// }
// if(T[rt].son[0] == 0)
// {
// rt = T[rt].son[1];
// T[rt].fa = 0;
// }
// else
// {
// int preid = T[rt].son[0];
// PushDown(preid);
// while(T[preid].son[1])
// {
// preid = T[preid].son[1];
// PushDown(preid);
// }
// Splay(preid, rt);
// T[preid].son[1] = T[rt].son[1];
// T[ T[rt].son[1] ].fa = preid;
// rt = preid;
// T[rt].fa = 0;
// PushUp(rt);
// }
// }
void Delete(int key) //删除值为key的节点1个,这个操作可能有问题。。。 { int x=Find(key); if(!x) return; if(T[x].num>1) { T[x].num--; PushUp(x); return; } int y=T[x].son[0]; while(T[y].son[1]) y=T[y].son[1]; int z=T[x].son[1]; while(T[z].son[0]) z=T[z].son[0]; if(!y && !z) { rt=0; return; } if(!y) { Splay(z, 0); T[z].son[0]=0; PushUp(z); return; } if(!z) { Splay(y, 0); T[y].son[1]=0; PushUp(y); return; } Splay(y, 0); Splay(z, y); T[z].son[0]=0; PushUp(z); PushUp(y); } int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为< { if(!rt) return 0; int x=rt, ret=0, y=0; while(x) { y=x; if(T[x].key <= key) { ret += T[T[x].son[0]].size + T[x].num; x=T[x].son[1]; } else x=T[x].son[0]; } Splay(y, 0); return ret; } // 这个删除太丑了 // void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r // { // if(!Find(l)) Insert(l);// 你这样写真的好吗? 泥煤 // int p=Prev(); // if(!Find(r)) Insert(r); // int q=next(); // if(!p && !q) // { // rt=0; // return; // } // if(!p) // { // T[rt].son[0]=0; // PushUp(rt); // return; // } // if(!q) // { // Splay(p, 0); // T[rt].son[1]=0; // PushUp(rt); // return; // } // Splay(p, q); // T[p].son[1]=0; // PushUp(p); // PushUp(q); // } }spt;
以上是关于Splay_Tree 模板(区间修改,旋转操作)的主要内容,如果未能解决你的问题,请参考以下文章