ezoj1852
要求写一个序列数据结构,支持区间加,区间翻转,区间最大值。
- 线段树结构能否支持区间翻转?
线段树节点记录一个 l s , r s ls,rs ls,rs,打翻转标记。每次下传就交换左右孩子。
- fhq-treap
以下标为关键字分裂, t r e a p treap treap中下标序列是始终不变的。理解成在下标序列上面挂的值在不停的变动。具体写法就是 s p l i t split split改成基于 s i z siz siz的。颇有“山不转水转”之感。
特别需要注意的是:需要额外记录每个点的值。 s p l i t split split和 m e r g e merge merge操作都要下放可能用到的标记。
跑得很慢。。。开 O 2 O2 O2就极快了。。
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 5e4 + 5;
struct poi {
int ls, rs, siz, rnd, rev;
LL mx, val, tag;
};
struct Tree {
poi tr[N];
int rt = 0, tot = 0;
inline void pushup(int k) {
tr[k].siz = 1; tr[k].mx = tr[k].val;
if ( tr[k].ls ) tr[k].siz += tr[ tr[k].ls ].siz, tr[k].mx = max(tr[k].mx, tr[ tr[k].ls ].mx);
if ( tr[k].rs ) tr[k].siz += tr[ tr[k].rs ].siz, tr[k].mx = max(tr[k].mx, tr[ tr[k].rs ].mx);
}
inline void pushdown(int k) {
if (!k) return ;
if (tr[k].rev) {
swap(tr[k].ls, tr[k].rs);
if (tr[k].ls) tr[ tr[k].ls ].rev ^= 1;
if (tr[k].rs) tr[ tr[k].rs ].rev ^= 1;
tr[k].rev = 0;
}
if (tr[k].tag) {
if (tr[k].ls) {
tr[ tr[k].ls ].mx += tr[k].tag;
tr[ tr[k].ls ].val += tr[k].tag;
tr[ tr[k].ls ].tag += tr[k].tag;
}
if (tr[k].rs) {
tr[ tr[k].rs ].mx += tr[k].tag;
tr[ tr[k].rs ].val += tr[k].tag;
tr[ tr[k].rs ].tag += tr[k].tag;
}
tr[k].tag = 0;
}
}
inline void newnode(int &k, int v) {
k = ++tot;
tr[k].ls = tr[k].rs = 0;
tr[k].siz = 1;
tr[k].rnd = rand();
tr[k].val = tr[k].mx = tr[k].rev = tr[k].tag = 0;
}
inline void split(int k, int &nls, int &nrs, int rk) {//所谓山不转水转
if (!k) {
nls = nrs = 0;
return ;
}
if (tr[k].tag || tr[k].rev) pushdown(k);
if (tr[ tr[k].ls ].siz >= rk){
nrs = k;
split(tr[k].ls, nls, tr[nrs].ls, rk);
}
else {
nls = k;
split(tr[k].rs, tr[nls].rs, nrs, rk - tr[ tr[k].ls ].siz - 1);
}
pushup(k);
}
inline void merge(int &k, int a, int b) {
if ((!a) || (!b)) {
k = a + b;
return ;
}
if (tr[a].tag || tr[a].rev) pushdown(a);
if (tr[b].tag || tr[b].rev) pushdown(b);
if (tr[a].rnd < tr[b].rnd) {
k = a;
merge(tr[k].rs, tr[a].rs, b);
}
else {
k = b;
merge(tr[k].ls, a, tr[b].ls);
}
pushup(k);
}
inline void insert(int v) {
int x = 0, y = 0, z = 0;
split(rt, x, y, v);
newnode(z, v);
merge(x, x, z);
merge(rt, x, y);
}
inline void update(int l, int r, int v) {
int x = 0, y = 0, z = 0;
split(rt, x, y, r);
split(x, x, z, l - 1);
tr[z].mx += v;
tr[z].val += v;
tr[z].tag += v;
merge(x, x, z);
merge(rt, x, y);
}
inline void rev(int l, int r) {
int x = 0, y = 0, z = 0;
split(rt, x, y, r);
split(x, x, z, l - 1);
tr[z].rev ^= 1;
merge(x, x, z);
merge(rt, x, y);
}
inline LL query(int l, int r) {
int x = 0, y = 0, z = 0;
split(rt, x, y, r);
split(x, x, z, l - 1);
LL res = tr[z].mx;
merge(x, x, z);
merge(rt, x, y);
return res;
}
inline void debug(int cur) {
if (tr[cur].ls ) debug(tr[cur].ls);
printf("cur = %d mx = %lld tag = %lld rev = %d ls = %d rs = %d\n", cur, tr[cur].mx, tr[cur].tag, tr[cur].rev, tr[cur].ls, tr[cur].rs);
if (tr[cur].rs ) debug(tr[cur].rs);
}
}T1;
int n, m;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-')f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int main() {
//freopen("data.in", "r", stdin);
//freopen("ezoj1852.out", "w", stdout);
srand(6628347);
n = read(); m = read();
for (int i = 1; i <= n; ++i)T1.insert(i);
//printf("rt = %d\n", T1.rt);
for (int i = 1; i <= m; ++i) {
int k, l, r, v;
k = read();
if (k == 1) {
l = read(); r = read(); v = read();
T1.update(l, r, v);
}
else
if (k == 2) {
l = read(); r = read();
T1.rev(l, r);
}
else {
l = read(); r = read();
printf("%lld\n", T1.query(l, r));
}
//T1.debug(T1.rt); printf("\n");
}
return 0;
}