最近把线段树给整理了一下,略有小成,还很弱。前几天队长跟我讲你这几天不用多干,专心把伸展树和差分给学了。从此之后的几天内都埋头在学习Splay。刚刚开始学习感觉不是很难,但是开始做题的时候感觉就有点吃力,特别是在做hdu1890处理Splya翻转+删除的时候,搞得我蛋疼了两天。网上的模板乱七八糟,几天过去了,对伸展树还是稍有领悟,现在真心感觉到伸展树的强大,线段树和平衡树能处理的问题伸展树也可以,但伸展树能处理的问题前面两者就不一定可以了。对于单点或者整段区间的插入删除翻转操作,线段树是望尘莫及的。下面是我的学习笔记,如有需要修改的地方,望指点,小弟感激不尽。
基础学习论文可以看看 杨思雨神牛的《伸展树的基本操作与运用》,以及Crash神牛的《运用伸展树解决数列维护问题》。
同时感谢ZAKIR、sha崽神牛的博客论文。
一些用Splay能很好处理的题目:
(splay入门题):
题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=1588
解题思路: 题目意思很显然,先建树,建树操作注意一下,单点插入,而不是整棵树一起建,因为这里对于现在插入的点只能很之前树中的点做比较。建完数之后就简单了,找比a大的最小值和找比a小的最大值。两者取最小的就行了。
代码:
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn=50005; 8 const int oo=1e9; 9 10 struct SplayTree 11 { 12 int son[maxn][2], pre[maxn], val[maxn]; 13 int rt, Size; 14 inline void Rotate(int x, int c) 15 { 16 int y=pre[x]; 17 son[y][!c]=son[x][c]; 18 pre[son[x][c]]=y; 19 pre[x]=pre[y]; 20 if(pre[x]) son[pre[y]][son[pre[y]][1]==y]=x; 21 son[x][c]=y; 22 pre[y]=x; 23 } 24 inline void Splay(int x, int goal) 25 { 26 while(pre[x]!=goal) 27 { 28 if(pre[pre[x]]==goal) 29 { 30 if(son[pre[x]][0]==x) 31 Rotate(x,1); 32 else 33 Rotate(x,0); 34 } 35 else 36 { 37 int y=pre[x], z=pre[y]; 38 if(son[z][0]==y) 39 { 40 if(son[y][0]==x) 41 Rotate(y,1), Rotate(x,1); 42 else 43 Rotate(x,0), Rotate(x,1); 44 } 45 else 46 { 47 if(son[y][1]==x) 48 Rotate(y,0), Rotate(x,0); 49 else 50 Rotate(x,1), Rotate(x,0); 51 } 52 } 53 } 54 if(goal==0) rt=x; 55 } 56 inline void NewNode(int y, int &x, int a) 57 { 58 x=++Size; 59 pre[x]=y; 60 val[x]=a; 61 son[x][0]=son[x][1]=0; 62 } 63 inline void init() 64 { 65 Size=0; 66 NewNode(0,rt,-oo); 67 NewNode(rt,son[rt][1],oo); 68 } 69 inline void Insert(int a) 70 { 71 int x=rt; 72 while(son[x][val[x]<a]) x=son[x][val[x]<a]; 73 NewNode(x,son[x][val[x]<a],a); 74 Splay(Size,0); 75 } 76 inline int fx_min(int a) ///找比a大的最小值 77 { 78 int x=rt,minn=oo; 79 while(x) 80 { 81 if(val[x]==a) return a; 82 if(val[x]>a) minn=min(minn,val[x]); 83 if(val[x]>a) x=son[x][0]; 84 else x=son[x][1]; 85 } 86 return minn; 87 } 88 inline int fx_max(int a) ///找比a小的最大值 89 { 90 int x=rt,maxx=-oo; 91 while(x) 92 { 93 if(val[x]==a) return a; 94 if(val[x]<a) maxx=max(maxx,val[x]); 95 if(val[x]<a) x=son[x][1]; 96 else x=son[x][0]; 97 } 98 return maxx; 99 } 100 }spt; 101 102 int main() 103 { 104 int n, a; 105 scanf("%d%d",&n,&a); 106 int ans=a; 107 spt.init(); 108 spt.Insert(a); 109 while(--n) 110 { 111 if(scanf("%d",&a)==-1) a=0; 112 ans+=min(fabs(a-spt.fx_min(a)),fabs(spt.fx_max(a)-a)); 113 spt.Insert(a); 114 } 115 cout << ans <<endl; 116 return 0; 117 }
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503
解题思路:这题就有点意思了,我开始傻傻的每次加我就加一遍,每次减就减一遍,发现后面操作的时候蛋疼了。其实这题很简单,用w值记录它的加减情况,加(减)操作加在w上加(减)val,当新来一个的时候你插入树中应该是以前工资未变化时的相对值,也就是val-w。关键在裁员怎么砍树了,最低工资为val,我们找到大于等于val最近的那个点(如果存在val这个值那么就是本身了),然后把这个点旋转到根,砍掉左子树,那么这样就算裁员了。查询第k多的时候要注意你开始就已经加了两个边界点,注意考虑这点。
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn=111111; 8 const int oo=2e9; 9 10 struct SplayTree 11 { 12 int son[maxn][2], pre[maxn], val[maxn], sum[maxn]; 13 int rt, Size; 14 inline void Push_up(int x) 15 { 16 sum[x]=sum[son[x][0]]+sum[son[x][1]]+1; 17 } 18 inline void Rotate(int x, int c) ///旋转操作,c=0表示左旋,c=1表示右旋 19 { 20 int y=pre[x]; 21 son[y][!c]=son[x][c]; 22 pre[son[x][c]]=y; 23 pre[x]=pre[y]; 24 if(pre[x]) son[pre[y]][son[pre[y]][1]==y]=x; 25 son[x][c]=y; 26 pre[y]=x; 27 Push_up(y); 28 } 29 inline void Splay(int x, int goal) 30 { 31 while(pre[x]!=goal) 32 { 33 if(pre[pre[x]]==goal) 34 { 35 if(son[pre[x]][0]==x) 36 Rotate(x,1); 37 else 38 Rotate(x,0); 39 } 40 else 41 { 42 int y=pre[x], z=pre[y]; 43 if(son[z][0]==y) 44 { 45 if(son[y][0]==x) 46 Rotate(y,1), Rotate(x,1); 47 else 48 Rotate(x,0), Rotate(x,1); 49 } 50 else 51 { 52 if(son[y][1]==x) 53 Rotate(y,0), Rotate(x,0); 54 else 55 Rotate(x,1), Rotate(x,0); 56 } 57 } 58 } 59 Push_up(x); 60 if(goal==0) rt=x; ///rt表示整棵树的根节点 61 } 62 inline void NewNode(int y, int &x, int a) 63 { 64 x=++Size; 65 pre[x]=y, val[x]=a, sum[x]=1; 66 son[x][0]=son[x][1]=0; 67 } 68 inline void init() 69 { 70 Size=0; 71 NewNode(0,rt,-oo); 72 NewNode(rt,son[rt][1],oo); 73 sum[rt]=2; 74 } 75 inline void Insert(int a) 76 { 77 int x=rt; 78 while(son[x][val[x]<a]) x=son[x][val[x]<a]; 79 NewNode(x,son[x][val[x]<a],a); 80 Splay(Size,0); 81 } 82 inline int Suc(int a) 83 { 84 int x=rt, res=oo; 85 while(x) 86 { 87 if(val[x]==a) return a; 88 if(val[x]>a) res=min(res,val[x]); 89 if(val[x]>a) x=son[x][0]; 90 else x=son[x][1]; 91 } 92 return res; 93 } 94 inline int Find(int a) 95 { 96 int x=rt; 97 while(x) 98 { 99 if(val[x]==a) return x; 100 if(val[x]>a) x=son[x][0]; 101 else x=son[x][1]; 102 } 103 return 0; 104 } 105 inline int DeleteSubTree(int a) 106 { 107 int x=Find(a), res=0; 108 if(x) 109 { 110 Splay(1,0); 111 Splay(x,1); 112 res=sum[son[x][0]]; 113 son[x][0]=0; 114 Splay(x,0); 115 } 116 return res; 117 } 118 inline int Select(int k, int f) 119 { 120 int x=rt; 121 while((sum[son[x][1]])!=k) ///这里要注意最右下边还有初始就有的无穷大节点 122 { 123 if(sum[son[x][1]]>k) x=son[x][1]; 124 else 125 { 126 k-=(sum[son[x][1]]+1); 127 x=son[x][0]; 128 } 129 } 130 Splay(x,f); 131 return val[x]; 132 } 133 } spt; 134 135 int main() 136 { 137 int n, m, a; 138 char op[5]; 139 spt.init(); 140 while(cin >> n >> m) 141 { 142 int ans=0, w=0; 143 while(n--) 144 { 145 scanf("%s%d",op,&a); 146 if(op[0]=='I') 147 { 148 a-=w; 149 if(a>=m-w) spt.Insert(a); 150 } 151 else if(op[0]=='A') 152 { 153 w+=a; 154 } 155 else if(op[0]=='S') 156 { 157 w-=a; 158 ans+=spt.DeleteSubTree(spt.Suc(m-w)); 159 } 160 else if(op[0]=='F') 161 { 162 if(a+2>spt.sum[spt.rt]) puts("-1"); 163 else printf("%d\n",spt.Select(a,0)+w); 164 } 165 } 166 cout << ans <<endl; 167 } 168 return 0; 169 }
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1208
解题思路:这题有点郁闷了。要注意的一点情况就是你建树不仅仅用狗,狗多了就人来找狗,狗没了就用人来建树,一个一个插入,换句话说,不仅狗可以等人,人也可以等狗。
删除操作可以考虑二叉树的性质,让删除的点旋转到根,找前驱结点或者后继结点来代替根节点即可。
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn=111111; 8 const int mod=1000000; 9 const int oo=0x3fffffff; 10 11 struct SplayTree 12 { 13 int son[maxn][2], pre[maxn], val[maxn], num[maxn]; 14 int rt, Size; 15 inline void Rotate(int x, int c) 16 { 17 int y=pre[x]; 18 son[y][!c]=son[x][c]; 19 pre[son[x][c]]=y; 20 pre[x]=pre[y]; 21 if(pre[x]) son[pre[y]][son[pre[y]][1]==y]=x; 22 son[x][c]=y; 23 pre[y]=x; 24 } 25 inline void Splay(int x, int goal) 26 { 27 while(pre[x]!=goal) 28 { 29 if(pre[pre[x]]==goal) 30 { 31 if(son[pre[x]][0]==x) 32 Rotate(x,1); 33 else 34 Rotate(x,0); 35 } 36 else 37 { 38 int y=pre[x], z=pre[y]; 39 if(son[z][0]==y) 40 { 41 if(son[y][0]==x) 42 Rotate(y,1), Rotate(x,1); 43 else 44 Rotate(x,0), Rotate(x,1); 45 } 46 else 47 { 48 if(son[y][1]==x) 49 Rotate(y,0), Rotate(x,0); 50 else 51 Rotate(x,1), Rotate(x,0); 52 } 53 } 54 } 55 if(goal==0) rt=x; 56 } 57 inline void NewNode(int y, int &x, int a) 58 { 59 x=++Size; 60 pre[x]=y; 61 val[x]=a; 62 son[x][0]=son[x][1]=0; 63 } 64 inline void init() 65 { 66 Size=0; 67 NewNode(0,rt,-oo); 68 NewNode(rt,son[rt][1],oo); 69 } 70 inline void Insert(int a) ///插入后即进行Splay,同步更新 71 { 72 int x=rt; 73 while(son[x][val[x]<a]) x=son[x][val[x]<a]; 74 NewNode(x,son[x][val[x]<a],a); 75 Splay(Size,0); 76 } 77 inline int fx_min(int a) ///大于a的最小值 78 { 79 int x=rt,minn=oo; 80 while(x) 81 { 82 if(val[x]==a) return a; 83 if(val[x]>a) minn=min(minn,val[x]); 84 if(val[x]>a) x=son[x][0]; 85 else x=son[x][1]; 86 } 87 return minn; 88 } 89 inline int fx_max(int a) ///小于a的最大值 90 { 91 int x=rt,maxx=-oo; 92 while(x) 93 { 94 if(val[x]==a) return a; 95 if(val[x]<a) maxx=max(maxx,val[x]); 96 if(val[x]<a) x=son[x][1]; 97 else x=son[x][0]; 98 } 99 return maxx; 100 } 101 inline int Find(int a) ///找位置 102 { 103 int x=rt; 104 while(x) 105 { 106 if(val[x]==a) return x; 107 if(val[x]>a) x=son[x][0]; 108 else x=son[x][1]; 109 } 110 return 0; 111 } 112 inline void Delete_pos(int x) ///删除节点 113 { 114 Splay(x,0); ///让x旋转到根节点 115 int tmp=son[rt][1]; 116 while(son[tmp][0]) tmp=son[tmp][0];///找根结点的后继,联想二叉树的删除操作就会明白 117 Splay(tmp,rt); ///将后继伸展到根下面,这时成为了根结点的右儿子。 118 son[tmp][0]=son[rt][0]; ///将后继作为根结点,根结点删除 119 pre[son[rt][0]]=tmp; 120 pre[tmp]=0; 121 rt=tmp; ///后继成为根节点 122 } 123 } spt; 124 125 int main() 126 { 127 int n, a, b, ans, num[2]; 128 while(cin >> n) 129 { 130 ans=0; 131 num[0]=num[1]=0; ///表示宠物和人的数量 132 spt.init(); 133 for(int i=0; i<n; i++) 134 { 135 scanf("%d%d",&a,&b); 136 if(num[!a]==0) ///不仅狗可以等人而且人还可以等狗,只有两者有一者之前就有,那么后者到来之时就可以选了,这里错的我蛋疼 137 { 138 num[a]++; 139 spt.Insert(b); 140 } 141 else 142 { 143 int minn=spt.fx_min(b); 144 int maxx=spt.fx_max(b); 145 ans=(ans+min(minn-b,b-maxx))%mod; 146 if(b-maxx<=minn-b) spt.Delete_pos(spt.Find(maxx)); 147 else spt.Delete_pos(spt.Find(minn)); 148 num[!a]--; 149 } 150 } 151 cout << ans%mod <<endl; 152 } 153 return 0; 154 }
(splay热身题):
POJ3468:
题目链接:http://poj.org/problem?id=3468
解题思路:
和线段树的成段更新没啥两样的,无非三点,标记,标记下传更新,总和上传更新。
(splay进阶题):
hdu 1890:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890
解题思路:
这题对所有节点进行建树,建树的时候我是用它的位置来进行建树,因为你要操作的只是位置。而题目要用到它的值的大小,所以开始的时候进行一次排序,记录位置下标。我觉得题目的难点就在下标处理和节点删除交换上。
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn=111111; 8 const int oo=0x3fffffff; 9 #define keytree son[son[rt][1]][0] 10 11 int cmp(pair<int,int>a,pair<int,int>b) 12 { 13 if(a.first!=b.first) return a.first<b.first; 14 else return a.second<b.second; 15 } 16 17 struct SplayTree 18 { 19 int son[maxn][2], pre[maxn],sz[maxn]; 20 int rt, Size; 21 inline void push_up(int x) 22 { 23 sz[x]=sz[son[x][0]]+sz[son[x][1]]+1; 24 } 25 inline void push_down(int x) 26 { 27 if(rev[x]) ///翻转标记 28 { 29 rev[son[x][0]]^=1; 30 rev[son[x][1]]^=1; 31 swap(son[x][0],son[x][1]); 32 rev[x]=0; 33 } 34 } 35 inline void Rotate(int x, int c) 36 { 37 int y=pre[x]; 38 push_down(y); 39 push_down(x); 40 son[y][!c]=son[x][c]; 41 pre[son[x][c]]=y; 42 pre[x]=pre[y]; 43 if(pre[x]) son[pre[y]][son[pre[y]][1]==y]=x; 44 son[x][c]=y; 45 pre[y]=x; 46 push_up(y); 47 } 48 inline void Splay(int x, int goal) 49 { 50 push_down(x); 51 while(pre[x]!=goal) 52 { 53 push_down(pre[pre[x]]); push_down(pre[x]);push_down(x); 54 if(pre[pre[x]]==goal) 55 { 56 if(son[pre[x]][0]==x) 57 Rotate(x,1); 58 else 59 Rotate(x,0); 60 } 61 else 62 { 63 int y=pre[x], z=pre[y]; 64 if(son[z][0]==y) 65 { 66 if(son[y][0]==x) 67 Rotate(y,1), Rotate(x,1); 68 else 69 Rotate(x,0), Rotate(x,1); 70 } 71 else 72 { 73 if(son[y][1]==x) 74 Rotate(y,0), Rotate(x,0); 75 else 76 Rotate(x,1), Rotate(x,0); 77 } 78 } 79 } 80 push_up(x); 81 if(goal==0) rt=x; 82 } 83 inline void RotateTo(int k, int goal) 84 { 85 int x=rt; 86 push_down(x); 87 while(sz[son[x][0]]+1!=k) 88 { 89 if(k<sz[son[x][0]]+1) 90 x=son[x][0]; 91 else 92 { 93 k-=(sz[son[x][0]]+1); 94 x=son[x][1]; 95 } 96 push_down(x); 97 } 98 Splay(x,goal); 99 } 100 inline void NewNode(int f, int &x, int a) 101 { 102 x=++Size; 103 pre[x]=f; 104 val[x]=a; 105 sz[x]=1; 106 rev[x]=0; 107 son[x][0]=son[x][1]=0; 108 } 109 inline void Maketree(int f, int &x, int l, int r) 110 { 111 if(l>r) return ; 112 int mid=(l+r)>>1; 113 NewNode(f,x,num[id[mid]].first); 114 mp[id[mid]]=x; 115 Maketree(x,son[x][0],l,mid-1); 116 Maketree(x,son[x][1],mid+1,r); 117 push_up(x); 118 } 119 inline void init(int n) 120 { 121 Size=0; 122 NewNode(0,rt,oo); 123 for(int i=1; i<=n; i++) 124 { 125 scanf("%d",&num[i].first); 126 num[i].second=i; 127 } 128 sort(num+1,num+n+1,cmp); 129 for(int i=1; i<=n; i++) 130 id[num[i].second]=i; 131 Maketree(rt,son[rt][0],1,n); 132 push_up(rt); 133 } 134 inline void vist(int x){ 135 if(x){ 136 printf("结点%2d : 左儿子 %2d 右儿子 %2d %2d flip:%d\n",x,son[x][0],son[x][1],val[x],rev[x]); 137 vist(son[x][0]); 138 vist(son[x][1]); 139 } 140 } 141 inline void Del(){ /// 删除+交换节点 142 int t=rt; 143 if(son[rt][1]) { 144 rt=son[rt][1]; ///直接覆盖要删除的节点,不要担心会破坏树的结构,因为下面会进行旋转操作,会保护树的结构 145 RotateTo(1,0); 146 son[rt][0]=son[t][0]; ///砍掉的节点的左子树接到根节点左边 147 if(son[rt][0]) pre[son[rt][0]]=rt; 148 } 149 else rt=son[rt][0]; 150 pre[rt]=0; 151 push_up(rt); 152 } 153 inline void Solve(int n) 154 { 155 for(int i=1; i<=n; i++) 156 { 157 Splay(mp[i],0); 158 //vist(1); 159 printf("%d",i+sz[son[rt][0]]); 160 rev[son[rt][0]]^=1; 161 Del(); 162 printf(i==n?"\n":" "); 163 } 164 } 165 pair<int,int>num[maxn]; 166 int id[maxn]; 167 int mp[maxn]; 168 int rev[maxn]; 169 int val[maxn]; 170 } spt; 171 172 int main() 173 { 174 int n; 175 while(cin >> n,n) 176 { 177 spt.init(n); 178 spt.Solve(n); 179 } 180 return 0; 181 }
hdu 3487 :
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487
解题思路:
题目意思很简单,两个操作:
CUT a b c :将[a,b]区间内数移到b位置后面。
FLIP a b : 翻转[a,b]区间内的数。
对于CUT操作,我们将第a-1位移到根节点,b+1位移到根节点的右孩子,砍掉根节点右孩子的左子树keyTree,然后再将第b-1,b位进行同样的操作,将keyTree接到b位的左孩子即可。对于最后答案的输出我们利用中序遍历即可,注意节点的权值在1-n,开始设的两个端点不能弄进去。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 #define keyTree (son[ son[rt][1] ][0]) 7 #define oo 0x3fffffff 8 const int maxn = 300030; 9 struct SplayTree 10 { 11 int sz[maxn]; 12 int son[maxn][2]; 13 int pre[maxn]; 14 int rt , top1 , top2; 15 int ss[maxn] , que[maxn]; 16 17 inline void Rotate(int x,int f) 18 { 19 int y = pre[x]; 20 push_down(y); 21 push_down(x); 22 son[y][!f] = son[x][f]; 23 pre[ son[x][f] ] = y; 24 pre[x] = pre[y]; 25 if(pre[x]) son[ pre[y] ][ son[pre[y]][1] == y ] = x; 26 son[x][f] = y; 27 pre[y] = x; 28 push_up(y); 29 } 30 inline void Splay(int x,int goal) 31 { 32 push_down(x); 33 while(pre[x] != goal) 34 { 35 if(pre[pre[x]] == goal) 36 { 37 Rotate(x , son[pre[x]][0] == x); 38 } 39 else 40 { 41 int y = pre[x] , z = pre[y]; 42 int f = (son[z][0] == y); 43 if(son[y][f] == x) 44 { 45 Rotate(x , !f) , Rotate(x , f); 46 } 47 else 48 { 49 Rotate(y , f) , Rotate(x , f); 50 } 51 } 52 } 53 push_up(x); 54 if(goal == 0) rt = x; 55 } 56 inline void RotateTo(int k,int goal) //把第k位的数转到goal下边 57 { 58 int x = rt; 59 push_down(x); 60 while(sz[ son[x][0] ] != k) 61 { 62 if(k < sz[ son[x][0] ]) 63 { 64 x = son[x][0]; 65 } 66 else 67 { 68 k -= (sz[ son[x][0] ] + 1); 69 x = son[x][1]; 70 } 71 push_down(x); 72 } 73 Splay(x,goal); 74 } 75 inline void erase(int x) //把以x为祖先结点删掉放进内存池,回收内存 76 { 77 int father = pre[x]; 78 int head = 0 , tail = 0; 79 for (que[tail++] = x ; head < tail ; head ++) 80 { 81 ss[top2 ++] = que[head]; 82 if(son[ que[head] ][0]) que[tail++] = son[ que[head] ][0]; 83 if(son[ que[head] ][1]) que[tail++] = son[ que[head] ][1]; 84 } 85 son[ father ][ son[father][1] == x ] = 0; 86 push_up(father); 87 } 88 void debug() 89 { 90 printf("%d\n",rt); 91 Treaval(rt); 92 } 93 void Treaval(int x) 94 { 95 if(x) 96 { 97 Treaval(son[x][0]); 98 printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d\n",x,son[x][0],son[x][1],pre[x],sz[x],val[x]); 99 Treaval(son[x][1]); 100 } 101 } 102 inline void push_down(int x) /*这是题目特定函数*/ 103 { 104 if(rev[x]) 105 { 106 rev[son[x][0]]^=1; 107 rev[son[x][1]]^=1; 108 swap(son[x][0],son[x][1]); 109 rev[x]= 0; 110 } 111 } 112 //把孩子状态更新上来 113 inline void push_up(int x) 114 { 115 sz[x] = 1 + sz[ son[x][0] ] + sz[ son[x][1] ]; 116 } 117 inline void NewNode(int &x,int c) 118 { 119 if (top2) x = ss[--top2];//用栈手动压的内存池 120 else x = ++top1; 121 son[x][0] = son[x][1] = pre[x] = 0; 122 sz[x] = 1; 123 rev[x]=0; 124 val[x] = c;/*这是题目特定函数*/ 125 add[x] = 0; 126 } 127 /*初始化*/ 128 inline void makeTree(int &x,int l,int r,int f) 129 { 130 if(l > r) return ; 131 int m = (l + r)>>1; 132 NewNode(x , num[m]); /*num[m]权值改成题目所需的*/ 133 makeTree(son[x][0] , l , m - 1 , x); 134 makeTree(son[x][1] , m + 1 , r , x); 135 pre[x] = f; 136 push_up(x); 137 } 138 inline void init(int n) /*这是题目特定函数*/ 139 { 140 son[0][0] = son[0][1] = pre[0] = sz[0] = 0; 141 add[0] = 0; 142 rt = top1 = 0; 143 //为了方便处理边界,加两个边界顶点 144 NewNode(rt , -oo); 145 NewNode(son[rt][1] , oo); 146 pre[top1] = rt; 147 sz[rt] = 2; 148 for (int i = 1 ; i <= n ; i ++) num[i]=i; 149 makeTree(keyTree , 1 , n , son[rt][1]); 150 push_up(son[rt][1]); 151 push_up(rt); 152 } 153 /*更新*/ 154 inline void Cut() /*这是题目特定函数*/ 155 { 156 int l , r , c; 157 scanf("%d%d%d",&l,&r,&c); 158 RotateTo(l-1,0); 159 RotateTo(r+1,rt); 160 int tp=keyTree; 161 keyTree=0; 162 push_up(son[rt][1]); 163 push_up(rt); 164 RotateTo(c,0); 165 RotateTo(c+1,rt); 166 keyTree=tp; 167 pre[tp]=son[rt][1]; 168 push_up(son[rt][1]); 169 push_up(rt); 170 } 171 inline void Rev() /*这是题目特定函数*/ 172 { 173 int l , r; 174 scanf("%d%d",&l,&r); 175 RotateTo(l-1,0); 176 RotateTo(r+1,rt); 177 rev[keyTree]^=1; 178 } 179 inline void dfs(int root, int n) 180 { 181 push_down(root); 182 if(son[root][0]!=0) 183 dfs(son[root][0],n); 184 if(1<=val[root]&&val[root]<=n) 185 { 186 if(!flag) 187 flag=1,printf("%d",val[root]); 188 else 189 printf(" %d",val[root]); 190 } 191 if(son[root][1]!=0) 192 dfs(son[root][1],n); 193 194 } 195 inline void Output(int n) 196 { 197 flag=0; 198 dfs(rt,n); 199 } 200 /*这是题目特定变量*/ 201 int flag; 202 int rev[maxn]; 203 int num[maxn]; 204 int val[maxn]; 205 int add[maxn]; 206 } spt; 207 208 int main() 209 { 210 int n , m; 211 while(scanf("%d%d",&n,&m)!=EOF) 212 { 213 if(n+m<0) break; 214 spt.init(n); 215 while(m--) 216 { 217 char op[6]; 218 scanf("%s",op); 219 if(op[0]=='C') 220 { 221 spt.Cut(); 222 } 223 else 224 { 225 spt.Rev(); 226 } 227 } 228 spt.Output(n); 229 puts(""); 230 } 231 return 0; 232 }
hdu 3436:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436
解题思路:有人说这题可以用线段树做,暂时还没想到。这里我领略的了伸展树的神奇之处。
有三种操作:Top x(将x提到第一位), Query x(询问元素x在第几位), Rank k (询问第k位的元素是谁)。
开始看题,so easy。再乍眼一看,擦,N最大10^8。所以必须要用离散化以及缩点,先离线处理 Query和Top出现的X值保存起来离散处理一下,然后将这些点各两点之间的点缩为一点处理,因为这些点不会变动。用一个pair数组记录这一段的范围。剩下的操作就留给伸展树了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <map> 5 #include <algorithm> 6 using namespace std; 7 8 #define keyTree (son[ son[rt][1] ][0]) 9 #define oo 1e8 10 const int maxn = 555555; 11 int n, m, T, top, ep; 12 int X[maxn]; 13 map<int,int>mp1, mp2; 14 pair<int,int>num[maxn]; 15 16 struct node 17 { 18 char ch[10]; 19 int x; 20 } f[maxn]; 21 22 int find(int tmp) 23 { 24 int l=1, r=top, mid; 25 while(l<=r) 26 { 27 mid=(l+r)>>1; 28 if(num[mid].first==tmp) return mid; 29 else if(num[mid].first<tmp) l=mid+1; 30 else r=mid-1; 31 } 32 } 33 34 struct SplayTree 35 { 36 int sz[maxn]; 37 int son[maxn][2]; 38 int pre[maxn]; 39 int rt , Size; 40 41 int ss[maxn]; 42 43 inline void Rotate(int x,int f) ///旋转操作,f=0表示左旋,f=1表示右旋 44 { 45 int y = pre[x]; 46 son[y][!f] = son[x][f]; 47 pre[ son[x][f] ] = y; 48 pre[x] = pre[y]; 49 if(pre[x]) son[ pre[y] ][ son[pre[y]][1] == y ] = x; 50 son[x][f] = y; 51 pre[y] = x; 52 push_up(y); 53 } 54 inline void Splay(int x,int goal) ///将x节点旋转到goal下边 55 { 56 57 while(pre[x] != goal) 58 { 59 60 if(pre[pre[x]] == goal) /// 父结点的父亲即为 goal,执行单旋转 61 { 62 Rotate(x , son[pre[x]][0] == x); 63 } 64 else 65 { 66 int y = pre[x] , z = pre[y]; 67 int f = (son[z][0] == y); 68 if(son[y][f] == x) 69 { 70 Rotate(x , !f) , Rotate(x , f); 71 } 72 else 73 { 74 Rotate(y , f) , Rotate(x , f); 75 } 76 } 77 } 78 push_up(x); 79 if(goal == 0) rt = x; 80 } 81 inline void push_up(int x) 82 { 83 int l=son[x][0], r=son[x][1]; 84 sz[x]=sz[ l ] + sz[ r ] + ss[x]; 85 } 86 inline void NewNode(int &x, int a) 87 { 88 x=++Size; 89 sz[x]=num[a].second-num[a].first+1; 90 ss[x]=num[a].second-num[a].first+1; 91 son[x][0]=son[x][1]=0; 92 } 93 inline void makeTree(int &x, int f, int l, int r) 94 { 95 if(l>r) return ; 96 int mid=(l+r)>>1; 97 NewNode(x,mid); 98 mp1[mid]=x; 99 mp2[x]=mid; 100 pre[x]=f; 101 makeTree(son[x][0],x,l,mid-1); 102 makeTree(son[x][1],x,mid+1,r); 103 push_up(x); 104 } 105 inline void init() 106 { 107 son[0][0]=son[0][1]=pre[0]=sz[0]=ss[0]=0; 108 Size=0; 109 NewNode(rt,0); //方便处理,只设一个节点,而不设两个 110 sz[rt]=1, ss[rt]=1; 111 pre[rt]=0; 112 makeTree(son[rt][0],rt,1,top); 113 push_up(rt); 114 } 115 inline int Suc_min() //找后继节点 116 { 117 int x=rt; 118 while(son[x][0]) x=son[x][0]; 119 return x; 120 } 121 inline void Insert(int x, int t) //插入到第一位 122 { 123 while(son[x][0]) x=son[x][0]; 124 sz[t]=ss[t]; 125 son[t][0]=son[t][1]=0; 126 son[x][0]=t; 127 pre[t]=x; 128 Splay(t,0); //插完要旋转,保持树平衡 129 } 130 inline void Remove(int tp) //移动到第一位,先删除(后继节点替代)再插入 131 { 132 int k=find(tp); 133 int x=mp1[k]; 134 Splay(x,0); 135 int t=rt; 136 if(son[rt][1]) 137 { 138 rt=son[rt][1]; 139 pre[rt]=0; 140 x=Suc_min(); 141 Splay(x,0); 142 son[rt][0]=son[t][0]; 143 if(son[rt][0]) pre[ son[rt][0] ]=rt; 144 } 145 else rt=son[rt][0]; 146 push_up(rt); 147 Insert(rt,t); 148 Splay(t,0); 149 } 150 inline void Query(int tp) 151 { 152 int k=find(tp); 153 int x=mp1[k]; 154 Splay(x,0); 155 printf("%d\n",sz[ son[rt][0] ]+1); 156 } 157 inline void Get_kth(int k) 158 { 159 int x = rt, kk=k; 160 while(1) 161 { 162 if(k <=sz[ son[x][0] ]) 163 { 164 x = son[x][0]; 165 } 166 else if(k>sz[ son[x][0] ]+ss[x]) 167 { 168 k -= (sz[ son[x][0] ] + ss[x]); 169 x = son[x][1]; 170 } 171 else break; 172 } 173 Splay(x,0); 174 printf("%d\n",num[ mp2[x] ].first+kk-sz[ son[rt][0] ]-1); 175 } 176 inline void Output(int x) 177 { 178 if(son[x][0]) Output(son[x][0]); 179 printf(" %d--%d ",num[mp2[x]].first,num[mp2[x]].second); 180 if(son[x][1]) Output(son[x][1]); 181 } 182 } spt; 183 184 int main() 185 { 186 cin >> T; 187 for(int tcase=1; tcase<=T; tcase++) 188 { 189 cin >> n >> m; 190 mp1.clear(), mp2.clear(); 191 top=0, ep=1, X[0]=0; 192 for(int i=1; i<=m; i++) 193 { 194 scanf("%s%d",f[i].ch,&f[i].x); 195 if(f[i].ch[0]=='Q'||f[i].ch[0]=='T') X[++top]=f[i].x; 196 } 197 sort(X+1,X+top+1); 198 for(int i=2; i<=top; i++) 199 if(X[i]!=X[ep]) X[++ep]=X[i]; 200 top=0; 201 for(int i=1; i<=ep; i++) 202 { 203 if(X[i]-X[i-1]>1) 204 { 205 num[++top].first=X[i-1]+1; 206 num[top].second=X[i]-1; 207 } 208 num[++top].first=X[i]; 209 num[top].second=X[i]; 210 } 211 num[++top].first=X[ep]+1; 212 num[top].second=oo; 213 spt.init(); 214 printf("Case %d:\n",tcase); 215 for(int i=1; i<=m; i++) 216 { 217 if(f[i].ch[0]=='T') spt.Remove(f[i].x); 218 else if(f[i].ch[0]=='Q') spt.Query(f[i].x); 219 else spt.Get_kth(f[i].x); 220 } 221 } 222 return 0; 223 }
spoj 4487:
题目链接:http://www.spoj.pl/problems/GSS6/
题目意思很简单。插入删除替代操作不难,求最长子段和和线段树的区间操作差不多。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #include <algorithm> 6 using namespace std; 7 8 #define keyTree (son[ son[rt][1] ][0]) 9 const int oo = 1e9; 10 const int maxn = 222222; 11 12 struct node 13 { 14 int lm, rm, sm; 15 }tree[maxn]; 16 17 struct SplayTree 18 { 19 int sz[maxn]; 20 int son[maxn][2]; 21 int pre[maxn]; 22 int rt, Size; 23 24 int num[maxn]; 25 int val[maxn]; 26 int sum[maxn]; 27 28 inline void Rotate(int x,int f) ///旋转操作,f=0表示左旋,f=1表示右旋 29 { 30 int y = pre[x]; 31 son[y][!f] = son[x][f]; 32 pre[ son[x][f] ] = y; 33 pre[x] = pre[y]; 34 if(pre[x]) son[ pre[y] ][ son[pre[y]][1] == y ] = x; 35 son[x][f] = y; 36 pre[y] = x; 37 push_up(y); 38 } 39 inline void Splay(int x,int goal) ///将x节点旋转到goal下边 40 { 41 while(pre[x] != goal) 42 { 43 if(pre[pre[x]] == goal) /// 父结点的父亲即为 goal,执行单旋转 44 { 45 Rotate(x , son[pre[x]][0] == x); 46 } 47 else 48 { 49 int y = pre[x] , z = pre[y]; 50 int f = (son[z][0] == y); 51 if(son[y][f] == x) 52 { 53 Rotate(x , !f) , Rotate(x , f); 54 } 55 else 56 { 57 Rotate(y , f) , Rotate(x , f); 58 } 59 } 60 } 61 push_up(x); 62 if(goal == 0) rt = x; 63 } 64 inline void RotateTo(int k,int goal) //把第k位的数转到goal下边 65 { 66 int x = rt; 67 while(sz[ son[x][0] ] != k) 68 { 69 if(k < sz[ son[x][0] ]) 70 { 71 x = son[x][0]; 72 } 73 else 74 { 75 k -= (sz[ son[x][0] ] + 1); 76 x = son[x][1]; 77 } 78 } 79 Splay(x,goal); 80 } 81 inline void push_up(int x) 82 { 83 84 int l=son[x][0], r=son[x][1]; 85 sz[x]=sz[l]+sz[r]+1; 86 sum[x]=sum[l] + sum[r] + val[x]; 87 88 tree[x].lm=max(tree[l].lm,sum[l]+val[x]+max(tree[r].lm,0)); 89 tree[x].rm=max(tree[r].rm,sum[r]+val[x]+max(tree[l].rm,0)); 90 tree[x].sm=max( max(tree[x].lm,tree[x].rm), max(tree[l].rm,0)+val[x]+max(tree[r].lm,0)); 91 tree[x].sm=max( tree[x].sm,max( tree[l].sm,tree[r].sm)); 92 } 93 inline void NewNode(int &x, int a) 94 { 95 x=++Size; 96 sz[x]=1; 97 son[x][0]=son[x][1]=0; 98 tree[x].lm=tree[x].rm=tree[x].sm=val[x]=sum[x]=a; 99 } 100 inline void makeTree(int &x, int f, int l, int r) 101 { 102 if(l>r) return ; 103 int mid=(l+r)>>1; 104 NewNode(x,num[mid]); 105 pre[x]=f; 106 makeTree(son[x][0],x,l,mid-1); 107 makeTree(son[x][1],x,mid+1,r); 108 push_up(x); 109 } 110 inline void init(int n) 111 { 112 son[0][0]=son[0][1]=pre[0]=sum[0]=0; 113 tree[0].lm=tree[0].rm=tree[0].sm=val[0]=-oo; 114 Size=0; 115 NewNode(rt,-oo); 116 NewNode(son[rt][1],oo); 117 sz[rt]=2; 118 pre[rt]=0; 119 pre[son[rt][1]]=rt; 120 for(int i=1; i<=n; i++) scanf("%d",num+i); 121 makeTree(keyTree,son[rt][1],1,n); 122 } 123 inline void Insert(int x, int y) 124 { 125 RotateTo(x-1,0); 126 RotateTo(x,rt); 127 NewNode(keyTree,y); 128 pre[keyTree]=son[rt][1]; 129 push_up(son[rt][1]); 130 push_up(rt); 131 } 132 inline void Delete(int x) 133 { 134 RotateTo(x-1,0); 135 RotateTo(x+1,rt); 136 keyTree=0; 137 push_up(son[rt][1]); 138 push_up(rt); 139 } 140 inline void Replace(int x, int y) 141 { 142 RotateTo(x,0); 143 val[rt]=y; 144 push_up(x); 145 } 146 inline void Query(int x, int y) 147 { 148 RotateTo(x-1,0); 149 RotateTo(y+1,rt); 150 printf("%d\n",tree[keyTree].sm); 151 } 152 }spt; 153 154 char CHAR() { 155 char res; 156 while (res = getchar(), !isalpha(res)); 157 return res; 158 } 159 inline void scanf_(int &num){ 160 char in; 161 bool neg=false; 162 while(((in=getchar()) > '9' || in<'0') && in!='-') ; 163 if(in=='-'){ 164 neg=true; 165 while((in=getchar()) >'9' || in<'0'); 166 } 167 num=in-'0'; 168 while(in=getchar(),in>='0'&&in<='9') 169 num*=10,num+=in-'0'; 170 if(neg) 171 num=0-num; 172 } 173 174 int main() 175 { 176 int n, m; 177 while(cin >> n) 178 { 179 spt.init(n); 180 cin >> m; 181 for(int i=0; i<m; i++) 182 { 183 char ch=CHAR(); 184 int x, y; 185 if(ch=='D') 186 { 187 scanf_(x); 188 spt.Delete(x); 189 } 190 else 191 { 192 scanf_(x), scanf_(y); 193 if(ch=='I') spt.Insert(x,y); 194 else if(ch=='R') spt.Replace(x,y); 195 else spt.Query(x,y); 196 } 197 } 198 } 199 return 0; 200 }
NOI2005 维修数列:
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1500
题解思路:很恶心的一道Splay Tree题,搞了我一天。初始化的时候0节点要lm,rm,sm要初始化为负无穷,不然会WA到死。
然后要注意几点:
1、Insert操作: 插入一段连续的数等价于再插入一颗Splay Tree。
2、Delete操作:删除操作不难,但是这里一个很关键的地方是会爆内存,解决方法?回收内存,重复利用已开辟内存的空间。
3、Make-Same and Revese:这两个操作起来差不多,关键要注意的是必须先下传标记进行处理再然后上传更新。为什么呢?因为对于求最长子序列和必定要你先进行翻转操作,这里蛋疼了很久。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 #define keyTree (son[ son[rt][1] ][0]) 8 #define oo 0x3fffffff 9 const int maxn = 555555; 10 int n, m; 11 12 struct SplayTree 13 { 14 int sz[maxn]; 15 int son[maxn][2]; 16 int pre[maxn]; 17 int rt , top1 , top2; 18 int ss[maxn]; ///回收内存池要用的数组 19 20 int num[maxn]; //应题目需要添加的数组 21 int val[maxn]; 22 int flag[maxn], rev[maxn]; 23 int lm[maxn], rm[maxn], sm[maxn]; 24 int sum[maxn]; 25 26 inline void Rotate(int x,int f) ///旋转操作,f=0表示左旋,f=1表示右旋 27 { 28 int y = pre[x]; 29 push_down(y); 30 push_down(x); 31 son[y][!f] = son[x][f]; 32 pre[ son[x][f] ] = y; 33 pre[x] = pre[y]; 34 if(pre[x]) son[ pre[y] ][ son[pre[y]][1] == y ] = x; 35 son[x][f] = y; 36 pre[y] = x; 37 push_up(y); 38 } 39 inline void Splay(int x,int goal) ///将x节点旋转到goal下边 40 { 41 push_down(x); 42 while(pre[x] != goal) 43 { 44 push_down(pre[pre[x]]); 45 push_down(pre[x]); 46 push_down(x); 47 if(pre[pre[x]] == goal) /// 父结点的父亲即为 goal,执行单旋转 48 { 49 Rotate(x , son[pre[x]][0] == x); 50 } 51 else 52 { 53 int y = pre[x] , z = pre[y]; 54 int f = (son[z][0] == y); 55 if(son[y][f] == x) 56 { 57 Rotate(x , !f) , Rotate(x , f); 58 } 59 else 60 { 61 Rotate(y , f) , Rotate(x , f); 62 } 63 } 64 } 65 push_up(x); 66 if(goal == 0) rt = x; 67 } 68 inline void RotateTo(int k,int goal) //把第k位的数转到goal下边 69 { 70 int x = rt; 71 push_down(x); 72 while(sz[ son[x][0] ] != k) //!这里要注意新加节点在不在右孩子 73 { 74 if(k < sz[ son[x][0] ]) 75 { 76 x = son[x][0]; 77 } 78 else 79 { 80 k -= (sz[ son[x][0] ] + 1); 81 x = son[x][1]; 82 } 83 push_down(x); 84 } 85 Splay(x,goal); 86 } 87 inline void pos_erase(int x) 88 { 89 if(!x) return ; 90 if(son[x][0]) pos_erase(son[x][0]); 91 ss[++top2]=x; 92 if(son[x][1]) pos_erase(son[x][1]); 93 } 94 inline void datasame(int x, int c) 95 { 96 if(!x) return ; 97 flag[x]=c; 98 val[x]=c; 99 sum[x]=sz[x]*c; 100 lm[x]=rm[x]=sm[x]=max(sum[x],c); 101 } 102 inline void datarev(int x) 103 { 104 if(!x) return ; 105 rev[x]^=1; 106 swap(son[x][0],son[x][1]); 107 swap(lm[x],rm[x]); 108 } 109 inline void push_up(int x) 110 { 111 int l=son[x][0], r=son[x][1]; 112 sz[x]= sz[ l ] + sz[ r ] +1; 113 sum[x]= sum[ l ] + sum[ r ] + val[x]; 114 115 lm[x]=max(lm[l],sum[l]+val[x]+max(lm[r],0)); 116 rm[x]=max(rm[r],sum[r]+val[x]+max(rm[l],0)); 117 sm[x]=max( max(lm[x],rm[x]), max(sm[l],sm[r])); 118 sm[x]=max(sm[x],max(rm[l],0)+val[x]+max(lm[r],0)); //!!判断该点选择性加靠近它的左右边界是否更大 119 } 120 inline void push_down(int x) 121 { 122 int l=son[x][0], r=son[x][1]; 123 if(flag[x]!=-oo) 124 { 125 datasame(l,flag[x]); 126 datasame(r,flag[x]); 127 flag[x]=-oo; 128 } 129 if(rev[x]) 130 { 131 datarev(l); 132 datarev(r); 133 rev[x]=0; 134 } 135 } 136 inline void NewNode(int &x, int a) 137 { 138 if(!top2) x=++top1; 139 else x=ss[top2--]; 140 sz[x]=1; 141 flag[x]=-oo; 142 rev[x]=0; 143 son[x][0]=son[x][1]=0; 144 lm[x]=rm[x]=sm[x]=val[x]=sum[x]=a; 145 } 146 inline void makeTree(int &x, int f, int l, int r) 147 { 148 if(l>r) return ; 149 int mid=(l+r)>>1; 150 NewNode(x,num[mid]); 151 pre[x]=f; 152 makeTree(son[x][0],x,l,mid-1); 153 makeTree(son[x][1],x,mid+1,r); 154 push_up(x); 155 } 156 inline void init() 157 { 158 son[0][0]=son[0][1]=pre[0]=rev[0]=sum[0]=val[0]=sz[0]=0; 159 lm[0]=rm[0]=sm[0]=flag[0]=-oo; ///!!这里要赋初值为-oo,不然会WA 160 top1=top2=0; 161 NewNode(rt,-oo); 162 NewNode(son[rt][1],oo); 163 sz[rt]=2; 164 pre[rt]=0; 165 pre[ son[rt][1] ]=rt; 166 167 for(int i=1; i<=n; i++) scanf("%d",num+i); 168 makeTree(keyTree,son[rt][1],1,n); 169 push_up(son[rt][1]); 170 push_up(rt); 171 } 172 inline void Insert() 173 { 174 int x, k; 175 scanf("%d%d",&x,&k); 176 for(int i=1; i<=k; i++) scanf("%d",num+i); 177 RotateTo(x,0); 178 RotateTo(x+1,rt); 179 makeTree(keyTree,son[rt][1],1,k); 180 pre[keyTree]=son[rt][1]; 181 push_up(son[rt][1]); 182 push_up(rt); 183 184 } 185 inline void Delete() 186 { 187 int x, k; 188 scanf("%d%d",&x,&k); 189 RotateTo(x-1,0); 190 RotateTo(x+k,rt); 191 pos_erase(keyTree); 192 keyTree=0; 193 push_up(son[rt][1]); 194 push_up(rt); 195 } 196 inline void MakeSame() 197 { 198 int x, k, c; 199 scanf("%d%d%d",&x,&k,&c); 200 RotateTo(x-1,0); 201 RotateTo(x+k,rt); 202 datasame(keyTree,c); //!! 这里要注意先下传标记,再上传更新 203 push_up(son[rt][1]); 204 push_up(rt); 205 } 206 inline void Rev() 207 { 208 int x, k; 209 scanf("%d%d",&x,&k); 210 RotateTo(x-1,0); 211 RotateTo(x+k,rt); 212 datarev(keyTree); //!! 这里要注意先下传标记,再上传更新 213 push_up(son[rt][1]); 214 push_up(rt); 215 } 216 inline void Get_Sum() 217 { 218 int x, k; 219 scanf("%d%d",&x,&k); 220 RotateTo(x-1,0); 221 RotateTo(x+k,rt); 222 printf("%d\n",sum[keyTree]); 223 } 224 inline void Max_Sum() 225 { 226 RotateTo(0,0); 227 RotateTo(sz[rt]-1,rt); 228 printf("%d\n",sm[keyTree]); 229 } 230 } spt; 231 232 233 int main() 234 { 235 while(cin >> n >> m) 236 { 237 spt.init(); 238 while(m--) 239 { 240 char ch[20]; 241 scanf("%s",ch); 242 if(ch[2]=='S') spt.Insert(); 243 else if(ch[2]=='L') spt.Delete(); 244 else if(ch[2]=='V') spt.Rev(); 245 else if(ch[2]=='K') spt.MakeSame(); 246 else if(ch[2]=='T') spt.Get_Sum(); 247 else if(ch[2]=='X') spt.Max_Sum(); 248 } 249 } 250 return 0; 251 }