【数据结构SPLAY】splay区间翻转,区间和查询,区间插入,区间删除,区间修改
2016-01-08 19:50
561 查看
#include<iostream> #include<algorithm> #include<stdio.h> #define maxn (200005) using namespace std; int ch[maxn][2],val[maxn],size[maxn],f[maxn]; int root,tot,n,m,a[maxn],add[maxn],sum[maxn]; bool flip[maxn]; //ch[i][1]表示节点i的左儿子 //ch[i][0]表示节点i的右儿子 //flip[i]表示节点i及以下的节点所组成的区间是否需要翻转 //val[i]表示节点i实际代表的值 //size[i]表示节点i的所有子节点的个数(包扩自己) //a[i]表示需要插入的序列 //add[i]表示节点i的lazy(不知道lazy的含义网上搜) //sum[i]表示节点i及子节点的总和(包括自己) //f[i]表示节点i的父亲 inline void pushup(int x)//要注意pushup在各个函数中的位置 //要先pushup儿子才能pushup父亲 { size[x]=size[ch[x][0]]+size[ch[x][1]]+1; sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x]; sum[x]+=add[ch[x][0]]*size[ch[x][0]]+add[ch[x][1]]*size[ch[x][1]]; } inline void pushdown(int x)//要注意位置 //要先pushdown父亲才能pushdown儿子 { if (flip[x]!=0) { flip[ch[x][0]]^=1; flip[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]);//要翻转区间即翻转两个儿子的位置 flip[x]=0; } if(ch[x][0]) add[ch[x][0]]+=add[x]; if(ch[x][1]) add[ch[x][1]]+=add[x]; val[x]+=add[x]; add[x]=0; } inline int is(int x)//判断x是f[x]的哪个子节点 { return ch[f[x]][1]==x; } inline void link(int y,int x,int d)//把x连成y的d儿子 { if (x) f[x]=y; ch[y][d]=x; if (x) pushup(x); pushup(y); } inline void newnode(int &x,int fa,int v)//建新点 { //&x似乎是表示此处的x更改了值之后相当于在全局改了x的值而不只是函数中更改x的值 tot++; x=tot; f[x]=fa; val[x]=v; if (fa==0) x=0; pushup(x); pushup(fa); } inline void rotate(int x,int d) //当x为d儿子时,把x往上旋转一层 { int y=f[x]; int z=f[y]; pushdown(z); pushdown(y); pushdown(x); link(y,ch[x][!d],d); if (z) link(z,x,is(y)); f[x]=z; link(x,y,!d); if (z) pushup(z); } inline void zig(int x)//当x为左儿子时向上旋转 { rotate(x,1); } inline void zag(int x)//当x为又儿子时向上旋转 { rotate(x,0); } inline void splay(int x,int goal=0)//把x旋转为goal的儿子 //这里的int goal=0表示如果没有传入goal这个参数时,直接把goal当做0使用 //当goal=0时即把x旋转为根节点 { pushdown(x); while (f[x]!=goal) { int y=f[x]; int z=f[y]; if (z==goal) { rotate(x,is(x)); break; } if (ch[z][1]==y) { if (ch[y][1]==x) zig(y),zig(x); //不写成zig(x),zig(x)是为了让树更加平衡,下同 else zag(x),zig(x); } else { if (ch[y][0]==x) zag(y),zag(x); else zig(x),zag(x); } pushup(x); } if (goal==0) root=x; pushup(x); if (goal) pushup(goal); } inline int pre(int x)//找x的前驱 { splay(x); x=ch[x][1]; while(ch[x][0]) x=ch[x][0]; return x; } inline int nex(int x)//找x的后继 { splay(x); x=ch[x][0]; while(ch[x][1]) x=ch[x][1]; return x; } inline void insert(int v)//有些题需要保持树的平衡性时,在整个序列的插入值为v的节点 { int x=root; while(ch[x][v<val[x]]) x=ch[x][v<val[x]]; newnode(ch[x][v<val[x]],x,v); splay(tot); } inline int getnum(int k,int x)//找到序列中第k个节点的编号(不是权值) { pushdown(x); if (x) pushup(x); if(size[ch[x][1]]+1==k) return x; else if (size[ch[x][1]]+1<k) return getnum(k-size[ch[x][1]]-1,ch[x][0]); else return getnum(k,ch[x][1]); } inline int build(int l,int r)//将(l,r)建成一课树 { if (l>r) return 0; tot++; int t=tot; int mid=(l+r)/2; val[t]=a[mid]; link(t,build(l,mid-1),1); link(t,build(mid+1,r),0); return t; } inline void insert_line(int k,int num)//在第k位后插入长为num的区间 { for (int i=1;i<=num;i++) scanf("%d",&a[i]); if (root==0) { root=build(1,num); return ; } int totk; if (k) totk=getnum(k,root); else totk=getnum(1,root); int nexk=nex(totk); if (nexk==0) link(totk,build(1,num),0); else { splay(totk); splay(nexk,totk); if (k==0) link(totk,build(1,num),1); else link(nexk,build(1,num),1); } } inline void del(int l,int r)//删除区间[l,r] { l=getnum(l,root); r=getnum(r,root); int prel=pre(l); int nexr=nex(r); if (prel==0&&nexr==0) root=0; else if (prel==0) splay(nexr),ch[nexr][1]=0,pushup(nexr); else if (nexr==0) splay(prel),ch[prel][0]=0,pushup(prel); else { splay(prel); splay(nexr,prel); ch[nexr][1]=0; pushup(nexr); } } inline void rev(int l,int r)//翻转区间[l,r] { l=getnum(l,root); r=getnum(r,root); int prel=pre(l); int nexr=nex(r); if (prel==0&&nexr==0) flip[root]^=1; else if (prel==0) { splay(nexr); flip[ch[nexr][1]]^=1; } else if (nexr==0) { splay(prel); flip[ch[prel][0]]^=1; } else { splay(prel); splay(nexr,prel); flip[ch[nexr][1]]^=1; pushup(nexr); } } inline void addv(int l,int r,int v)//给区间[l,r]内的值增加v { l=getnum(l,root); r=getnum(r,root); int prel=pre(l); int nexr=nex(r); if (prel==0&&nexr==0) add[root]+=v; else if (prel==0) { splay(nexr); add[ch[nexr][1]]+=v; } else if (nexr==0) { splay(prel); add[ch[prel][0]]+=v; } else { splay(prel); splay(nexr,prel); add[ch[nexr][1]]+=v; } } inline int query(int l,int r)//查询区间[l,r]的和 { l=getnum(l,root); r=getnum(r,root); int prel=pre(l); int nexr=nex(r); if (prel==0&&nexr==0) printf("%d\n",sum[root]); else if (prel==0) { splay(nexr); printf("%d\n",sum[ch[nexr][1]]); } else if (nexr==0) { splay(prel); printf("%d\n",sum[ch[prel][0]]); } else { splay(prel); splay(nexr,prel); printf("%d\n",sum[ch[nexr][1]]); } } //void putt()//调试时用的函数 //{ // for (int i=1;i<=tot;i++) // cout<<ch[i][0]<<' '<<ch[i][1]<<' '<<sum[i]<<endl; //} int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); root=build(1,n); f[root]=0; // for (int j=1;j<=20;j++) // cout<<val[getnum(j,root)]<<' '; // cout<<endl; for (int i=1;i<=m;i++) { // putt(); // cout<<endl; char c; int a,b,lps; cin>>c>>a>>b; if (c=='R') rev(a,b); else if (c=='D') del(a,b); else if (c=='I') insert_line(a,b); else if (c=='A') scanf("%d",&lps),addv(a,b,lps); else query(a,b); // for (int j=1;j<=20;j++) // cout<<val[getnum(j,root)]<<' '; // cout<<"root :"<<val[root]<<endl; // cout<<endl; } }
还没有将splay的所有用法写完…..
待续…..
相关文章推荐
- 10 归并两个有序链表
- java 中的JDK封装的数据结构和算法解析(集合类)----顺序表 List 之 ArrayList
- 数据结构:树、二叉树、二叉查找树
- 3-5-表达式求值-栈和队列-第3章-《数据结构》课本源码-严蔚敏吴伟民版
- C语言数据结构——单链表
- 无向图的邻接多重表结构,存储结构及基本功能实现(最全)
- c++ 数据结构 *** 栈的应用——计算器
- 数据结构之各种数据结构插入、删除、查找的时间复杂度
- 数据结构 2-11设顺序表va中的数据元素递增有序。试写一算法,将x插入到顺序表的适当位置上,以保持该表的有序性。
- 数据结构之多维数组理解
- Scalaz(24)- 泛函数据结构: Tree-数据游览及维护
- Scalaz(24)- 泛函数据结构: Tree-数据游览及维护
- 算法导论7:选择算法和数据结构准备 2016.1.7
- C语言数据结构——顺序表
- ArrayList和LinkedList
- 数据结构--排序-查询-二叉树各种遍历-求深度
- 数据结构概论
- swift学习02-数据结构和类
- 数据结构-链表快速排序
- 03.C#数据结构ArrayList、Hashtable、List泛型、Dictionary字典