「BZOJ 1251」序列终结者「Splay」

像线段树那样,维护一个懒标记就行

#include <algorithm>
#include <cstdio>
using namespace std;

namespace Splay {
	const int N = 1e5 + 10;
	int root, ch[N][2], sz[N], fa[N];
	int tag[N], mx[N], va[N];
	bool rev[N];
	inline int dir(int x) {
		return ch[fa[x]][1] == x;
	}
	inline void upd(int x) {
		sz[x] = 1 + sz[ch[x][0]] + sz[ch[x][1]];
		mx[x] = max(va[x], max(mx[ch[x][0]], mx[ch[x][1]]));
	}
	inline void rotate(int x) {
		int d = dir(x), f = fa[x];
		if(fa[x] = fa[f]) ch[fa[x]][dir(f)] = x;
		if(ch[f][d] = ch[x][d ^ 1]) fa[ch[f][d]] = f;
		fa[ch[x][d ^ 1] = f] = x;
		upd(f), upd(x);
	}
	inline void pushd(int x) {
		if(tag[x]) {
			if(ch[x][0]) {
				tag[ch[x][0]] += tag[x];
				va[ch[x][0]] += tag[x];
				mx[ch[x][0]] += tag[x];
			}
			if(ch[x][1]) {
				tag[ch[x][1]] += tag[x];
				va[ch[x][1]] += tag[x];
				mx[ch[x][1]] += tag[x];
			}
			tag[x] = 0;
		}
		if(rev[x]) {
			rev[x] = 0;
			rev[ch[x][0]] ^= 1;
			rev[ch[x][1]] ^= 1;
			swap(ch[x][0], ch[x][1]);
		}
	}
	int build(int l, int r) {
		if(l > r) return 0;
		int m = l + r >> 1; sz[m] = 1;
		if(l == r) return l;
		int L = build(l, m - 1), R = build(m + 1, r);
		if(ch[m][0] = L) fa[L] = m;
		if(ch[m][1] = R) fa[R] = m;
		sz[m] += sz[L] + sz[R];
		return m;
	}
	int top, st[N];
	void splay(int u, int tof = 0) {
		top = 0;
		for(int x = u; fa[x]; x = fa[x]) st[top ++] = fa[x];
		while(top --) pushd(st[top]);
		pushd(u);
		for(int x = u; fa[x] != tof; rotate(x))
			if(fa[fa[x]] != tof) rotate(dir(x) == dir(fa[x]) ? fa[x] : x);
		if(!tof) root = u;
	}
	int kth(int u, int k) {
		int v = u;
		while(1) {
			pushd(v);
			if(k <= sz[ch[v][0]]) v = ch[v][0];
			else {
				k -= sz[ch[v][0]] + 1;
				if(k == 0) break ;
				v = ch[v][1];
			}
		}
		splay(v, fa[u]);
		return v;
	}
	void reverse(int l, int r) {
		int u = kth(root, r + 1);
		int v = kth(ch[u][0], l - 1);
		rev[ch[v][1]] ^= 1;
	}
	void addv(int l, int r, int val) {
		int u = kth(root, r + 1);
		int v = kth(ch[u][0], l - 1);
		tag[ch[v][1]] += val;
		mx[ch[v][1]] += val;
		va[ch[v][1]] += val;
	}
	int qmax(int l, int r) {
		int u = kth(root, r + 1);
		int v = kth(ch[u][0], l - 1);
		return mx[ch[v][1]];
	}
}

int main() {
	int n, m; scanf("%d%d", &n, &m);
	Splay :: mx[0] = - 1 << 30;
	Splay :: root = Splay :: build(1, n + 2);
	for(int i = 1, op, l, r, v; i <= m; i ++) {
		scanf("%d%d%d", &op, &l, &r); ++ l; ++ r;
		if(op == 1) {
			scanf("%d", &v);
			Splay :: addv(l, r, v);
		}
		if(op == 2) Splay :: reverse(l, r);
		if(op == 3) printf("%d\n", Splay :: qmax(l, r));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值