BZOJ 1251: 序列终结者

Description

给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。 最开始所有元素都是0。

Input

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

Output

对于每个第3种操作,给出正确的回答。

Sample Input

1
2
3
4
5
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4

Sample Output

1
2

Hint

N<=50,000,M<=100,000。

Solution

Splay,翻转操作打标记,注意询问中给的是序列中的编号,和Splay中的编号不一样——我是按照序列先后顺序建的Splay,因此询问中的编号要转为Splay中第K大的是多少。

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 1<<30;
int getint() {
    int r = 0, k = 1; char c = getchar();
    for (; '0' > c || c > '9'; c = getchar()) if (c == '-') k = -1;
    for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
    return r * k;
}
const int maxn = 50009;
int mx[maxn], A[maxn], lazy[maxn], c[maxn][2], rev[maxn], fa[maxn], root, siz[maxn];
void add(int x, int v) {
	mx[x] += v;
	A[x] += v;
	lazy[x] += v;
}
void pu(int x) {
	int &l = c[x][0], &r = c[x][1];
	mx[x] = A[x];
	siz[x] = 1;
	if (l) {
		mx[x] = max(mx[l], mx[x]);
		siz[x] += siz[l];
	}
	if (r) {
		mx[x] = max(mx[r], mx[x]);
		siz[x] += siz[r];
	}
}
void pd(int x) {
	int &l = c[x][0], &r = c[x][1];
	if (rev[x]) {
		if (l) rev[l] ^= 1;
		if (r) rev[r] ^= 1;
		rev[x] = 0;
		swap(l, r);
	}
	if (lazy[x]) {
		if (l) add(l, lazy[x]);
		if (r) add(r, lazy[x]);
		lazy[x] = 0;
	}
}
int build(int l, int r) {
	if (l == r) {
		siz[l] = 1;
		return l;
	}
	int mid = (l + r) >> 1;
	if (mid > l) {
		c[mid][0] = build(l, mid-1);
		fa[c[mid][0]] = mid;
	}
	if (r > mid) {
		c[mid][1] = build(mid+1, r);
		fa[c[mid][1]] = mid;
	}
	pu(mid);
	return mid;
}
void rotate(int x) {
	int y = fa[x], z = fa[y], a = (c[y][1] == x), b = a ^ 1;
	if (z) {c[z][c[z][1]==y] = x;}
	fa[x] = z; fa[y] = x; if (c[x][b]) fa[c[x][b]] = y;
	c[y][a] = c[x][b]; c[x][b] = y;
	pu(y); pu(x);
}
void splay(int x, int pos = 0) {
	while (fa[x] != pos) {
		int y = fa[x], z = fa[y];
		if (z != pos) {
			if (c[z][0] == y ^ c[y][0] == x) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	if (pos == 0) root = x;
}
int K(int x, int key) {
	pd(x);
	int l = c[x][0], ls = siz[l];
	if (key <= ls) return K(l, key);
	if (key == ls + 1) return x;
	return K(c[x][1], key - ls - 1);
}
int query(int l, int r) {
	int lid = K(root, l);
	int rid = K(root, r+2);
	splay(lid);
	splay(rid, lid);
	return mx[c[rid][0]];
}
void rever(int l, int r) {
	int lid = K(root, l);
	int rid = K(root, r+2);
	splay(lid);
	splay(rid, lid);
	rev[c[rid][0]] ^= 1;
}
void change(int l, int r, int v) {
	int lid = K(root, l);
	int rid = K(root, r+2);
	splay(lid);
	splay(rid, lid);
	add(c[rid][0], v);
}
int n, m;
int main() {
	n = getint(); m = getint();
	root = build(1, n+2);
	int k, l, r, v;
	while (m--) {
		k = getint(); l = getint(); r = getint();
		if (k == 1) {
			v = getint();
			change(l, r, v);
		} else if (k == 2) {
			rever(l, r);
		} else {
			printf("%d\n", query(l, r));
		}
	}
    return 0;
}