题目描述
给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作:
将[L,R]这个区间内的所有数加上V。
将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。
求[L,R]这个区间中的最大值。
最开始所有元素都是0。
输入输出格式
输入格式:
第一行两个整数N,M。M为操作个数。
以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
输出格式:
对于每个第3种操作,给出正确的回答。
输入输出样例
输入样例#1:
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
输出样例#1:
2
说明
N≤50000,M≤100000。
主要思路:FHQ Treap区间操作
算是一道模板题吧。主要是在维护区间加和区间翻转上。
重点就是打标记。其实区间翻转的标记方式在文艺平衡树那道题里面有用到过。就是在做一个标记,标记区间是否翻转。然后在有标记的节点上交换左右子树即可。部分代码如下:
// z[rt].col表示区间加的懒标记
// z[rt].coll表示区间翻转的懒标记
// z[rt].ch[0]表示rt节点的左子树
// z[rt].ch[1]表示rt节点的右子树
// 这个代码是下方标记的函数
inline void push_col(int rt) {
if(z[rt].col) {
if(z[rt].ch[0]) { // 分类讨论
z[z[rt].ch[0]].col += z[rt].col;
z[z[rt].ch[0]].maxx += z[rt].col;
z[z[rt].ch[0]].w += z[rt].col;
}
if(z[rt].ch[1]) {
z[z[rt].ch[1]].col += z[rt].col;
z[z[rt].ch[1]].maxx += z[rt].col;
z[z[rt].ch[1]].w += z[rt].col;
}
z[rt].col = 0; // 最后去掉标记
}
if(z[rt].coll) {
if(z[rt].ch[0]) z[z[rt].ch[0]].coll ^= 1;
if(z[rt].ch[1]) z[z[rt].ch[1]].coll ^= 1;
swap(z[rt].ch[0], z[rt].ch[1]); // 交换
z[rt].coll = 0; // 去标记
}
}
要注意的是在split和merge时加上push_col和update的操作。
code:
附带debug代码。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <queue>
#include <map>
#include <vector>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 50010
#define inf 1 << 30
#define ll long long
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch > '9' || ch < '0') { if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
struct tree{
int ch[2], pri, sze, w;
int maxx;
int col, coll;
} z[mn];
inline void update(int rt) {
z[rt].sze = 1;
z[rt].maxx = z[rt].w;
if(z[rt].ch[0]) {
z[rt].sze += z[z[rt].ch[0]].sze;
z[rt].maxx = max(z[rt].maxx, z[z[rt].ch[0]].maxx);
}
if(z[rt].ch[1]) {
z[rt].sze += z[z[rt].ch[1]].sze;
z[rt].maxx = max(z[rt].maxx, z[z[rt].ch[1]].maxx);
}
}
inline void push_col(int rt) {
if(z[rt].col) {
if(z[rt].ch[0]) {
z[z[rt].ch[0]].col += z[rt].col;
z[z[rt].ch[0]].maxx += z[rt].col;
z[z[rt].ch[0]].w += z[rt].col;
}
if(z[rt].ch[1]) {
z[z[rt].ch[1]].col += z[rt].col;
z[z[rt].ch[1]].maxx += z[rt].col;
z[z[rt].ch[1]].w += z[rt].col;
}
z[rt].col = 0;
// update(rt);
}
if(z[rt].coll) {
if(z[rt].ch[0]) z[z[rt].ch[0]].coll ^= 1;
if(z[rt].ch[1]) z[z[rt].ch[1]].coll ^= 1;
swap(z[rt].ch[0], z[rt].ch[1]);
z[rt].coll = 0;
}
}
int cnt;
inline int newnode(int w = 0) {
z[++cnt].maxx = w;
z[cnt].w = w;
z[cnt].pri = rand();
z[cnt].sze = 1;
z[cnt].col = z[cnt].coll = 0;
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(z[x].pri < z[y].pri) {
push_col(x);
z[x].ch[1] = merge(z[x].ch[1], y);
update(x);
return x;
} else {
push_col(y);
z[y].ch[0] = merge(x, z[y].ch[0]);
update(y);
return y;
}
}
inline void split(int rt, int k, int &x, int &y) {
if(!rt) x = y = 0;
else {
push_col(rt);
if(k <= z[z[rt].ch[0]].sze) {
y = rt, split(z[rt].ch[0], k, x, z[rt].ch[0]);
} else {
x = rt, split(z[rt].ch[1], k - z[z[rt].ch[0]].sze - 1, z[rt].ch[1], y);
}
update(rt);
}
}
inline void debug(int rt) {
if(!rt) return;
if(z[rt].ch[0]) debug(z[rt].ch[0]);
printf("%d %d %d %d
", z[rt].w, z[rt].maxx, z[rt].pri, z[rt].sze);
if(z[rt].ch[1]) debug(z[rt].ch[1]);
}
int n, m, rot, xx, yy, zz;
int main() {
n = read(), m = read();
go(i, 1, n, 1) {
rot = merge(rot, newnode(0));
}
go(i, 1, m, 1) {
int s = read(), l = read(), r = read(), v;
if(s == 1) {
v = read();
split(rot, r, xx, zz);
split(xx, l - 1, xx, yy);
z[yy].col += v;
z[yy].maxx += v;
z[yy].w += v;
rot = merge(merge(xx, yy), zz);
} else if(s == 2) {
split(rot, r, xx, zz);
split(xx, l - 1, xx, yy);
z[yy].coll ^= 1;
rot = merge(merge(xx, yy), zz);
} else if(s == 3) {
split(rot, r, xx, zz);
split(xx, l - 1, xx, yy);
printf("%d
", z[yy].maxx);
rot = merge(merge(xx, yy), zz);
}
}
// debug(rot);
return 0;
}