题解 P4146 【序列终结者】

题目描述

给定一个长度为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;
}
原文地址:https://www.cnblogs.com/yizimi/p/10071621.html