BZOJ 1251 序列终结者(Splay)

 

题目大意

 

网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。【问题描述】 给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将 [L, R] 这个区间内的所有数加上 V。 2. 将 [L,R] 这个区间翻转,比如 1 2 3 4 变成 4 3 2 1。3. 求 [L,R] 这个区间中的最大值。最开始所有元素都是 0。

 

第一行两个整数 N,M。M 为操作个数。以下 M 行,每行最多四个整数,依次为 K, L, R, V。K 表示是第几种操作,如果不是第 1 种操作则 K 后面只有两个数。对于每个第3种操作,给出正确的回答。

 

【数据范围】N<=50000,M<=100000。

 

做法分析

 

这题还真不能用 线段树 做,Splay 是一个不错的选择

 

对于操作 1 将所有 [L, R] 中的数加上一个常量,可以对 Splay 树中的节点增加一个 add 域,表示以该节点为根中序遍历所得的数列中每个数要增加 add,每次执行的时候,先将 L-1 旋转到根,再把 R+1 旋转成根的儿子节点,那么,[L, R] 区间的数列就在 R+1 的左子树中了,对 R+1 的左儿子执行更新操作即可,类似于线段树的懒操作

对于操作 2 将所有 [L, R] 中的数翻转,可以对 Splay 树中的节点增加一个 rev 域,表示以该节点为根中序遍历所得的数列是否需要翻转,更新的时候还是和操作 1 一样,将 L-1 旋转到根,R+1 旋转成为 L-1 的孩子,直接对 R+1 的左儿子更新

对于操作 3,增加一个 Max 域,表示以该节点为根中序遍历得到的数列中最大值是多少,询问时,将 L-1 旋转到根,R+1 旋转成 L-1 的孩子,询问 R-1 的左儿子的 Max 即可

 

这里说一点细节:由于是维护数列,且涉及到区间翻转操作,所以还要增加一个 Size 域,表示以它为根的中序遍历得到的数列的个数是多少,用它来实现数列中的定位

由于涉及到翻转和统一加权操作,pushDown 和 pushUp 操作一定要想好在哪些地方需要执行

 

参考代码

 

 

BZOJ 1251 序列终结者(Splay)
  1 #include <iostream>

  2 #include <cstring>

  3 #include <cstdio>

  4 

  5 using namespace std;

  6 

  7 const int N=100005, INF=0x7fffffff;

  8 

  9 struct Splay_Tree {

 10     struct Node {

 11         int val, Max, add, Size, son[2];

 12         bool rev;

 13         void init(int _val) {

 14             val=Max=_val, Size=1;

 15             add=rev=son[0]=son[1]=0;

 16         }

 17     } T[N];

 18     int fa[N], root;

 19 

 20     void pushUp(int x) {

 21         T[x].Max=T[x].val, T[x].Size=1;

 22         if(T[x].son[0]) {

 23             T[x].Max=max(T[x].Max, T[T[x].son[0]].Max);

 24             T[x].Size+=T[T[x].son[0]].Size;

 25         }

 26         if(T[x].son[1]) {

 27             T[x].Max=max(T[x].Max, T[T[x].son[1]].Max);

 28             T[x].Size+=T[T[x].son[1]].Size;

 29         }

 30     }

 31 

 32     void pushDown(int x) {

 33         if(x==0) return;

 34         if(T[x].add) {

 35             if(T[x].son[0]) {

 36                 T[T[x].son[0]].val+=T[x].add;

 37                 T[T[x].son[0]].Max+=T[x].add;

 38                 T[T[x].son[0]].add+=T[x].add;

 39             }

 40             if(T[x].son[1]) {

 41                 T[T[x].son[1]].val+=T[x].add;

 42                 T[T[x].son[1]].Max+=T[x].add;

 43                 T[T[x].son[1]].add+=T[x].add;

 44             }

 45             T[x].add=0;

 46         }

 47         if(T[x].rev) {

 48             if(T[x].son[0]) T[T[x].son[0]].rev^=1;

 49             if(T[x].son[1]) T[T[x].son[1]].rev^=1;

 50             swap(T[x].son[0], T[x].son[1]);

 51             T[x].rev=0;

 52         }

 53     }

 54 

 55     void Rotate(int x, int kind) {

 56         int y=fa[x], z=fa[y];

 57         T[y].son[!kind]=T[x].son[kind], fa[T[x].son[kind]]=y;

 58         T[x].son[kind]=y, fa[y]=x;

 59         T[z].son[T[z].son[1]==y]=x, fa[x]=z;

 60         pushUp(y);

 61     }

 62 

 63     void Splay(int x, int goal) {

 64         if(x==goal) return;

 65         while(fa[x]!=goal) {

 66             int y=fa[x], z=fa[y];

 67             pushDown(z), pushDown(y), pushDown(x);

 68             int rx=T[y].son[0]==x, ry=T[z].son[0]==y;

 69             if(z==goal) Rotate(x, rx);

 70             else {

 71                 if(rx==ry) Rotate(y, ry);

 72                 else Rotate(x, rx);

 73                 Rotate(x, ry);

 74             }

 75         }

 76         pushUp(x);

 77         if(goal==0) root=x;

 78     }

 79 

 80     int Select(int pos) {

 81         int u=root;

 82         pushDown(u);

 83         while(T[T[u].son[0]].Size!=pos) {

 84             if(pos<T[T[u].son[0]].Size) u=T[u].son[0];

 85             else {

 86                 pos-=T[T[u].son[0]].Size+1;

 87                 u=T[u].son[1];

 88             }

 89             pushDown(u);

 90         }

 91         return u;

 92     }

 93 

 94     void update(int L, int R, int val) {

 95         int u=Select(L-1), v=Select(R+1);

 96         Splay(u, 0);

 97         Splay(v, u);

 98         T[T[v].son[0]].Max+=val;

 99         T[T[v].son[0]].val+=val;

100         T[T[v].son[0]].add+=val;

101     }

102 

103     void Reverse(int L, int R) {

104         int u=Select(L-1), v=Select(R+1);

105         Splay(u, 0);

106         Splay(v, u);

107         T[T[v].son[0]].rev^=1;

108     }

109 

110     int query(int L, int R) {

111         int u=Select(L-1), v=Select(R+1);

112         Splay(u, 0);

113         Splay(v, u);

114         return T[T[v].son[0]].Max;

115     }

116 

117     int build(int L, int R) {

118         if(L>R) return 0;

119         if(L==R) return L;

120         int mid=(L+R)>>1, sL, sR;

121         T[mid].son[0]=sL=build(L, mid-1);

122         T[mid].son[1]=sR=build(mid+1, R);

123         fa[sL]=fa[sR]=mid;

124         pushUp(mid);

125         return mid;

126     }

127 

128     void init(int n) {

129         T[0].init(-INF), T[1].init(-INF), T[n+2].init(-INF);

130         for(int i=2; i<=n+1; i++) T[i].init(0);

131         root=build(1, n+2), fa[root]=0;

132         fa[0]=0, T[0].son[1]=root, T[0].Size=0;

133     }

134 };

135 

136 Splay_Tree hehe;

137 

138 int main() {

139     int n, m;

140     scanf("%d%d", &n, &m);

141     hehe.init(n);

142     for(int i=0, a, b, c, d; i<m; i++) {

143         scanf("%d", &a);

144         if(a==1) {

145             scanf("%d%d%d", &b, &c, &d);

146             hehe.update(b, c, d);

147         }

148         else if(a==2) {

149             scanf("%d%d", &b, &c);

150             hehe.Reverse(b, c);

151         }

152         else {

153             scanf("%d%d", &b, &c);

154             printf("%d\n", hehe.query(b, c));

155         }

156     }

157     return 0;

158 }
BZOJ 1251

 

 

题目链接 & AC 通道

 

BZOJ 1251 序列终结者

 

 

 

你可能感兴趣的:(play)