序列终结者
Description
网上有许多题,就是给定一个序列,要你支持几种操作: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。
Input
第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。
Output
对于每个第3种操作,给出正确的回答。
Sample Input
4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output
2
【数据范围】
N<=50000,M<=100000。
Solution
一些基本的区间操作,这里不用splay而用fhq treap来实现,实际5200ms,而且建treap都没有用上线性的笛卡尔树建树方法,这样相比之下hzwer的splay要8000+ms,效果还是比较明显的
Code
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define X first
#define Y second
#define MS(_) memset(_, 0, sizeof(_))
#define PB push_back
#define MP make_pair
#define CLEAR\
root = merge(A.X, merge(B.X, B.Y));
#define debug(...) fprintf(stderr, __VA_ARGS__)
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
const int INF = 2147483647;
struct Treap{
Treap *lc, *rc;
int fix, size, val, delta, mx, tag;
Treap(int _val):fix(rand()), size(1), val(_val), lc(NULL), rc(NULL), tag(false), delta(0), mx(0) {}
inline void add(int d){ mx += d; val += d; delta += d; }
inline void rev() { tag ^= 1; }
inline void sink(){
if (delta){
if (lc) lc->add(delta); if (rc) rc->add(delta);
delta = 0;
}
if (tag){
if (lc) lc->rev(); if (rc) rc->rev();
swap(lc, rc); tag ^= 1;
}
}
inline void update(){
size = 1 + (lc ? lc->size : 0) + (rc ? rc->size : 0);
mx = max(val, max(lc ? lc->mx : -INF, rc ? rc->mx : -INF));
}
}*root;
typedef pair<Treap*, Treap*> droot;
int n, m;
inline int sz(Treap *x) {return x ? x->size : 0;}
Treap *merge(Treap *A, Treap *B){
if (!A) return B;
if (!B) return A;
A->sink(); B->sink();
if (A->fix < B->fix){
A->rc = merge(A->rc, B); A->update();
return A;
}else{
B->lc = merge(A, B->lc); B->update();
return B;
}
}
droot split(Treap *A, int k){ droot ans;
if (!A) return droot(NULL, NULL);
A->sink();
if (sz(A->lc) >= k){
ans = split(A->lc, k);
A->lc = ans.Y; A->update();
ans.Y = A;
}else{
ans = split(A->rc, k-sz(A->lc)-1);
A->rc = ans.X; A->update();
ans.X = A;
}
return ans;
}
inline void insert(int k, int value){
Treap *tmp;
droot y = split(root, k-1);
tmp = new Treap(value);
root = merge(merge(y.X, tmp), y.second);
}
int main(){
read(n); read(m);
rep(i, 1, n) insert(i, 0);
rep(i, 1, m){ int opt, l, r, v; droot A, B;
read(opt); read(l); read(r);
A = split(root, l-1); B = split(A.Y, r-l+1);
if (opt == 1){ read(v); B.X->add(v); CLEAR }
else if (opt == 2){ B.X->rev(); CLEAR }
else { printf("%d\n", B.X->mx); CLEAR }
}
return 0;
}