Splay Tree-伸展树学习笔记

      最近把线段树给整理了一下,略有小成,还很弱。前几天队长跟我讲你这几天不用多干,专心把伸展树和差分给学了。从此之后的几天内都埋头在学习Splay。刚刚开始学习感觉不是很难,但是开始做题的时候感觉就有点吃力,特别是在做hdu1890处理Splya翻转+删除的时候,搞得我蛋疼了两天。网上的模板乱七八糟,几天过去了,对伸展树还是稍有领悟,现在真心感觉到伸展树的强大,线段树和平衡树能处理的问题伸展树也可以,但伸展树能处理的问题前面两者就不一定可以了。对于单点或者整段区间的插入删除翻转操作,线段树是望尘莫及的。下面是我的学习笔记,如有需要修改的地方,望指点,小弟感激不尽。

 

       基础学习论文可以看看 杨思雨神牛的《伸展树的基本操作与运用》,以及Crash神牛的《运用伸展树解决数列维护问题》。

       同时感谢ZAKIR、sha崽神牛的博客论文。

      

一些用Splay能很好处理的题目:

(splay入门题):

HNOI2002]营业额统计

题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=1588

解题思路: 题目意思很显然,先建树,建树操作注意一下,单点插入,而不是整棵树一起建,因为这里对于现在插入的点只能很之前树中的点做比较。建完数之后就简单了,找比a大的最小值和找比a小的最大值。两者取最小的就行了。

代码: 

View Code
  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 }

[NOI2004]郁闷的出纳员

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503

解题思路:这题就有点意思了,我开始傻傻的每次加我就加一遍,每次减就减一遍,发现后面操作的时候蛋疼了。其实这题很简单,用w值记录它的加减情况,加(减)操作加在w上加(减)val,当新来一个的时候你插入树中应该是以前工资未变化时的相对值,也就是val-w。关键在裁员怎么砍树了,最低工资为val,我们找到大于等于val最近的那个点(如果存在val这个值那么就是本身了),然后把这个点旋转到根,砍掉左子树,那么这样就算裁员了。查询第k多的时候要注意你开始就已经加了两个边界点,注意考虑这点。

View Code
  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 }

[HNOI2004]宠物收养所   

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1208

解题思路:这题有点郁闷了。要注意的一点情况就是你建树不仅仅用狗,狗多了就人来找狗,狗没了就用人来建树,一个一个插入,换句话说,不仅狗可以等人,人也可以等狗。

删除操作可以考虑二叉树的性质,让删除的点旋转到根,找前驱结点或者后继结点来代替根节点即可。

View Code
  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

解题思路:

这题对所有节点进行建树,建树的时候我是用它的位置来进行建树,因为你要操作的只是位置。而题目要用到它的值的大小,所以开始的时候进行一次排序,记录位置下标。我觉得题目的难点就在下标处理和节点删除交换上。

View Code
  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,开始设的两个端点不能弄进去。

View Code
  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 }
View Code

 

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 }
View Code

 

 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 }
View Code

 

 

你可能感兴趣的:(tree)