Splay树小结
http://blog.csdn.net/acm_cxlove/article/details/7815019 附上cxlove大神的博客链接,最近是跟着上面的题目做的。
刚学的时候感觉好难,显示照着大白皮上面敲的模板,然后网上各种看论文,感觉指针写还是太繁琐,还是直接数组写的精炼。感觉Splay树确实强大,可以解决好多序列问题。感觉Splay树的核心是Key_Tree = ch[ch[root][1]][0]这个东西的使用,因为这棵子树就代表了你当前要修改,或者查询的区间,当然单点修改也可以这样做。
Splay树的核心操作有两个:一个是Splay操作(把当前点转到根节点的操作),一个是把第k个点转到根(其实不一定是根)。
下面附上这两种操作的模板:
kind == 0 表示左旋,kind == 1表示右旋
void Rotate(int x,int kind){ int y = pre[x]; Push_Down(y); Push_Down(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]){ ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; Push_Up(y); }
//把x节点旋转到goal下面 void Splay(int x,int goal){ Push_Down(x); while(pre[x] != goal){ Push_Down(pre[pre[x]]); Push_Down(pre[x]); Push_Down(x); if(pre[pre[x]] == goal){ Rotate(x,ch[pre[x]][0] == x); } else{ int y = pre[x]; int kind = (ch[pre[y]][0] == y); if(ch[y][kind] == x){ Rotate(x,!kind); Rotate(x,kind); } else{ Rotate(y,kind); Rotate(x,kind); } } } Push_Up(x); if(!goal) root = x; }
///把第k个节点转到goal下面 void RotateTo(int k,int goal){ int x = root; Push_Down(x); while(sz[ch[x][0]] != k){ if(k < sz[ch[x][0]]){ x = ch[x][0]; } else{ k -= (sz[ch[x][0]]+1); x = ch[x][1]; } Push_Down(x); } Splay(x,goal); }上面的模板入门不能好好理解得话,画几张图就会了。
区间操作的时候,查询或者修改[l,r]这段区间,那么我们把RotateTo(l-1,0),RotateTo(r+1,root)那么,此时Key_Tree的子树就代表这段要查询或者修改的区间。这个是伸展树里面区间操作的核心的核心!!!
然后区间操作还有一个关键的地方就是:Push_Up,Push_Down操作,和线段树很像。还有就是初始化了,一般我都是在序列头,序列尾多加一个节点,这样就能保证不会越界了,还有就是初始化的时候最好把0这种节点的值附为一个不会影响答案的值。
下面附上几道题目(可以跟着练手):
HYSBZ 1588 营业额统计:
HDU 3436 Queue_jumpers
这题主要要把一个区间缩成一个点。写起来可能稍微麻烦一点
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <map> #define LL long long #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) #define Key_Tree ch[ch[root][1]][0] #define MAXN 110000 using namespace std; int n,m; int TQ[MAXN],cnt_TQ; int N,ssz[MAXN],l[MAXN]; map <int,int> mat; struct Commends{ char str[10]; int num; }cmd[MAXN]; struct SplayTree{ int ch[MAXN][2],sz[MAXN],pre[MAXN],key[MAXN],root,tot,sum[MAXN],val[MAXN],pos[MAXN]; int flip[MAXN]; void Rotate(int x,int kind){ int y = pre[x]; Push_Down(y); Push_Down(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]){ ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; Push_Up(y); } void Splay(int x,int goal){ Push_Down(x); while(pre[x] != goal){ Push_Down(pre[pre[x]]); Push_Down(pre[x]); Push_Down(x); if(pre[pre[x]] == goal){ Rotate(x,ch[pre[x]][0] == x); } else{ int y = pre[x]; int kind = (ch[pre[y]][0] == y); if(ch[y][kind] == x){ Rotate(x,!kind); Rotate(x,kind); } else{ Rotate(y,kind); Rotate(x,kind); } } } Push_Up(x); if(!goal) root = x; } void RotateTo(int k,int goal){ int x = root; Push_Down(x); while(sz[ch[x][0]] != k){ if(k < sz[ch[x][0]]){ x = ch[x][0]; } else{ k -= (sz[ch[x][0]]+1); x = ch[x][1]; } Push_Down(x); } Splay(x,goal); } //debug部分copy from hh void Treaval(int x) { if(x) { Treaval(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,key = %2d,sum = %2d,val = %2d \n",x,ch[x][0],ch[x][1],pre[x],sz[x],key[x],sum[x],val[x]); Treaval(ch[x][1]); } } void debug() {printf("%d\n",root);Treaval(root);} //以上debug void NewNode(int& x,int father,int k,int v){ x = ++tot; pre[x] = father; key[x] = k; val[x] = v; ch[x][0] = ch[x][1] = 0; sz[x] = 1; flip[x] = 0; } void Push_Up(int x){ sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; sum[x] = sum[ch[x][0]]+ sum[ch[x][1]] + val[x]; } void Push_Down(int x){ if(flip[x]){ flip[ch[x][0]] ^= 1; flip[ch[x][1]] ^= 1; flip[x] = 0; swap(ch[x][1],ch[x][0]); } } void Build(int& x,int l,int r,int father){ if(l > r) return; int mid = (l+r) >> 1; NewNode(x,father,mid,ssz[mid]); pos[mid] = x; Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); Push_Up(x); } void Init(){ root = tot = 0; ch[0][1] = ch[0][0] = pre[0] = sz[0] = 0; NewNode(root,0,0,1); NewNode(ch[root][1],root,0,1); sz[root] = 2; Build(Key_Tree,1,N,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } void UpDate(int x){ ch[x][1] = ch[x][0] = 0; sz[x] = 1; sum[x] = val[x]; } void Top(int x){ RotateTo(0,0); Splay(x,root); int a = Get_Pre(x); if(a == -1) return; Splay(a,x); pre[Key_Tree] = root; pre[ch[ch[root][1]][1]] = Key_Tree; ch[Key_Tree][1] = ch[ch[root][1]][1]; ch[root][1] = Key_Tree; Push_Up(ch[root][1]); Push_Up(root); UpDate(x); RotateTo(1,root); pre[x] = ch[root][1]; Key_Tree = x; Push_Up(ch[root][1]); Push_Up(root); } int Query(int x){ //debug(); Splay(x,root); return sum[Key_Tree]+1; } int Rank(int x,int k){ if(k >= sum[ch[x][0]] && k < sum[ch[x][0]] + val[x]) return (l[key[x]] + k - (sum[ch[x][0]])); if(k < sum[ch[x][0]]) return Rank(ch[x][0],k); return Rank(ch[x][1],k - (sum[ch[x][0]] + val[x])); } void solve(){ //debug(); FOR(i,0,m){ if(cmd[i].str[0] == 'T') {Top(pos[mat[cmd[i].num]]);} else if(cmd[i].str[0] == 'Q') {printf("%d\n",Query(pos[mat[cmd[i].num]]));} else {printf("%d\n",Rank(root,cmd[i].num));} } } int Get_Pre(int x){ Push_Down(x); x = ch[x][0]; while(x){ Push_Down(x); while(ch[x][1]){ x = ch[x][1]; Push_Down(x); } return x; } return -1; } int Get_Next(int x){ Push_Down(x); x = ch[x][1]; while(x){ Push_Down(x); while(ch[x][0]){ x = ch[x][0]; Push_Down(x); } return x; } return -1; } }spt; void Read(){ cnt_TQ = 0; FOR(i,0,m){ scanf("%s%d",cmd[i].str,&cmd[i].num); if(cmd[i].str[0] != 'R'){ TQ[cnt_TQ ++] = cmd[i].num; } } sort(TQ,TQ+cnt_TQ); N = 0; if(TQ[0] == 1){ mat[1] = 1; ssz[++N] = 1; l[N] = 1; } else{ ssz[++N] = TQ[0]-1; l[N] = 1; mat[TQ[0]] = ++N; ssz[N] = 1; l[N] = TQ[0]; } FOR(i,1,cnt_TQ){ if(TQ[i] == TQ[i-1]) continue; if(TQ[i] == TQ[i-1] + 1){ mat[TQ[i]] = ++N; ssz[N] = 1; l[N] = TQ[i]; } else{ ssz[++N] = TQ[i] - TQ[i-1]-1; l[N] = TQ[i-1] + 1; mat[TQ[i]] = ++N; ssz[N] = 1; l[N] = TQ[i]; } } if(TQ[cnt_TQ-1] != n){ ssz[++N] = n - TQ[cnt_TQ-1]; l[N] = TQ[cnt_TQ-1] + 1; } } int main() { //freopen("test.in","r",stdin); int T,tCase = 0; scanf("%d",&T); while(T--){ printf("Case %d:\n",++tCase); scanf("%d%d",&n,&m); Read(); spt.Init(); spt.solve(); } return 0; }HDU 1890 Robotic Sort
HDU 3487 Play With Chain
没什么难的地方:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #define LL long long #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) #define Key_Tree ch[ch[root][1]][0] #define MAXN 330000 using namespace std; int n,m,num[MAXN],cnt; char cmd[10]; struct SplayTree{ int ans[MAXN]; int ch[MAXN][2],sz[MAXN],pre[MAXN],key[MAXN],root,tot; int flip[MAXN]; void Rotate(int x,int kind){ int y = pre[x]; Push_Down(y); Push_Down(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]){ ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; Push_Up(y); } void Splay(int x,int goal){ Push_Down(x); while(pre[x] != goal){ Push_Down(pre[pre[x]]); Push_Down(pre[x]); Push_Down(x); if(pre[pre[x]] == goal){ Rotate(x,ch[pre[x]][0] == x); } else{ int y = pre[x]; int kind = (ch[pre[y]][0] == y); if(ch[y][kind] == x){ Rotate(x,!kind); Rotate(x,kind); } else{ Rotate(y,kind); Rotate(x,kind); } } } Push_Up(x); if(!goal) root = x; } void RotateTo(int k,int goal){ int x = root; Push_Down(x); while(sz[ch[x][0]] != k){ if(k < sz[ch[x][0]]){ x = ch[x][0]; } else{ k -= (sz[ch[x][0]]+1); x = ch[x][1]; } Push_Down(x); } Splay(x,goal); } //debug部分copy from hh void Treaval(int x) { if(x) { Treaval(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d \n",x,ch[x][0],ch[x][1],pre[x],sz[x],key[x]); Treaval(ch[x][1]); } } void Debug() {printf("%d\n",root);Treaval(root);} //以上debug void Build(int& x,int l,int r,int father){ if(l > r) return; int mid = (l+r) >> 1; NewNode(x,father,num[mid]); Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); Push_Up(x); } void Init(){ root = tot = 0; ch[0][1] = ch[0][0] = pre[0] = sz[0] = 0; NewNode(root,0,0); NewNode(ch[root][1],root,0); sz[root] = 2; Build(Key_Tree,0,n-1,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } int Get_Pre(int x){ Push_Down(x); x = ch[x][0]; while(x){ Push_Down(x); while(ch[x][1]){ x = ch[x][1]; Push_Down(x); } return x; } return -1; } int Get_Next(int x){ Push_Down(x); x = ch[x][1]; while(x){ Push_Down(x); while(ch[x][0]){ x = ch[x][0]; Push_Down(x); } return x; } return -1; } void NewNode(int& x,int father,int k){ x = ++tot; pre[x] = father; key[x] = k; ch[x][0] = ch[x][1] = 0; sz[x] = 1; flip[x] = 0; } void Push_Up(int x){ sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } void Push_Down(int x){ if(flip[x]){ flip[ch[x][0]] ^= 1; flip[ch[x][1]] ^= 1; flip[x] = 0; swap(ch[x][1],ch[x][0]); } } void Flip(int l,int r){ RotateTo(l-1,0); RotateTo(r+1,root); flip[Key_Tree] ^= 1; } void Cut(int l,int r,int k){ RotateTo(l-1,0); RotateTo(r+1,root); int p = Key_Tree; ch[ch[root][1]][0] = 0; sz[ch[root][1]] = sz[ch[ch[root][1]][1]] + 1; Push_Up(root); //Debug(); RotateTo(k,0); RotateTo(k+1,root); pre[p] = ch[root][1]; ch[ch[root][1]][0] = p; Push_Up(ch[root][1]); Push_Up(root); } void Print(int x){ Push_Down(x); if(ch[x][0]) {Print(ch[x][0]);} if(cnt == 0 && key[x] != 0) {printf("%d",key[x]);cnt++;} else if(key[x] != 0) {printf(" %d",key[x]);cnt++;} if(ch[x][1]) {Print(ch[x][1]);} } }spt; int main() { //freopen("test.in","r",stdin); while(~scanf("%d%d",&n,&m) && (n >= 0 || m >= 0)){ FOR(i,0,n) num[i] = i+1; spt.Init(); //spt.Debug(); FOR(i,0,m){ scanf("%s",cmd); int l,r,k; if(cmd[0] == 'C'){ scanf("%d%d%d",&l,&r,&k); spt.Cut(l,r,k); //spt.Debug(); } else{ scanf("%d%d",&l,&r); spt.Flip(l,r); } } cnt = 0; spt.Print(spt.root); printf("\n"); } return 0; }POJ 3580 SuperMemo
NOI 2005 维修数列
非常BT的一题
版权声明:本文为博主原创文章,未经博主允许不得转载。