[Summary of knowledge] Some routines of Splay simple interval operation

Introduction

The efficiency of Splay in maintaining the number set is not outstanding, but it can efficiently maintain the sequence and perform some operations on the sequence, even the line segment tree cannot do (such as interval flipping).

Therefore, mastering Splay is still very important, and it is not difficult to understand.

Range Selection

The most classic application Splay than the range flipped up.

「Luogu P3391」 【Template】 Literary and artistic balance tree

Obviously, the number of columns of the original order is given to explain our Splay should be \ (L \ text {number} <X \ text {number} <R \ text {number} \) , it should be used contribution of Instead of inserting one by one. The time complexity is obviously \ (\ Theta (n) \) .

What about interval flipping? We should first find this interval.

How to find This is what many interval operations have in common.

Suppose the interval to be flipped now is \ ([l, r] \) .

We first use a search function to find the node number at the position \ (l-1, r + 1 \) in the sequence , which is recorded as \ (x, y \) .

Then \ (X \) rotating (The splay operation) to the root on the \ (Y \) threaded onto (X \) \ right at son .

Then this magical Splay looks like this:

GoMwv9.png

Then just do sth on the root of this subtree in the middle.

Since the operation interval will always move forward / backward by one position, we generally insert \ (-\ infty \) as the virtual node at the front and back .

inline void f(int l,int r) {
	l = select(l), r = select(r + 2);
        /*位置 1 和 n + 2 都是虚拟结点*/
	splay(l, 0), splay(r, l);
        /*do sth.*/
}

Modification

For interval modification operations, such as interval flipping, usually not directly done, but marked like a line segment tree.

Then we also need to have a mark to download like a line segment tree, so when will it download? In the selectfunction while looking for the next pass to the side.

inline int select(int k) {
	for (register int rt = root; rt;) {
		pushdown(rt); /*<- 在这里下传*/
		if (k == size[ch[rt][0]] + 1) return rt;
		if (k < size[ch[rt][0]] + 1) rt = ch[rt][0];
		else k -= size[ch[rt][0]] + 1, rt = ch[rt][1];
	}
}

Query

This is very simple, just select the interval first, and then get the information in the middle subtree.

Problem: "Luogu P2042" [NOI2005] Maintain the sequence

Code Sample

#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
using namespace std;

const int N = 5e5 + 5;
const long long inf = 1e18;
typedef long long LL;

int ch[N][2], fa[N], size[N];
LL val[N], sum[N], lmax[N], rmax[N], mmax[N];
bool cov[N], rev[N];

LL ary[N];
int n, q, total = 0, root;
stack<int> rec;

inline int create() {
	if (rec.empty()) return ++total;
	int ret = rec.top();
	return rec.pop(), ret;
}
inline void clear(int rt) {
	ch[rt][0] = ch[rt][1] = fa[rt] = 0;
	val[rt] = lmax[rt] = rmax[rt] = 0;
	mmax[rt] = -inf;
	cov[rt] = rev[rt] = 0;
}

inline void maintain(int rt) {
	size[rt] = size[ch[rt][0]] + size[ch[rt][1]] + 1;
	sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]] + val[rt];
	lmax[rt] = max(lmax[ch[rt][0]], lmax[ch[rt][1]] + sum[ch[rt][0]] + val[rt]);
	rmax[rt] = max(rmax[ch[rt][1]], rmax[ch[rt][0]] + sum[ch[rt][1]] + val[rt]);
	mmax[rt] = max(max(mmax[ch[rt][0]], mmax[ch[rt][1]]), lmax[ch[rt][1]] + rmax[ch[rt][0]] + val[rt]);
}
inline void pushdown(int rt) {
	int &l = ch[rt][0], &r = ch[rt][1];
	if (cov[rt]) {
		rev[rt] = cov[rt] = 0;
		if (l) cov[l] = 1, val[l] = val[rt], sum[l] = val[rt] * size[l];
		if (r) cov[r] = 1, val[r] = val[rt], sum[r] = val[rt] * size[r];
		if (val[rt] >= 0) {
			if (l) lmax[l] = rmax[l] = mmax[l] = sum[l];
			if (r) lmax[r] = rmax[r] = mmax[r] = sum[r];
		} else {
			if (l) lmax[l] = rmax[l] = 0, mmax[l] = val[l];
			if (r) lmax[r] = rmax[r] = 0, mmax[r] = val[r];
		}
	}
	if (rev[rt]) {
		rev[rt] = 0;
		if (l) rev[l] ^= 1;
		if (r) rev[r] ^= 1;
		swap(lmax[l], rmax[l]);
		swap(lmax[r], rmax[r]);
		swap(ch[l][0], ch[l][1]);
		swap(ch[r][0], ch[r][1]);
	}
}

inline int get(int rt) {
	return rt == ch[fa[rt]][1];
}
inline void rotate(int x) {
	int y = fa[x], z = fa[y], c = get(x);
	ch[y][c] = ch[x][c ^ 1];
	fa[ch[x][c ^ 1]] = y;
	ch[x][c ^ 1] = y;
	fa[y] = x, fa[x] = z;
	if (z) ch[z][y == ch[z][1]] = x;
	maintain(y), maintain(x);
}
inline void splay(int x,int g) {
	for (register int f = fa[x]; (f = fa[x]) != g; rotate(x))
		if(fa[f] != g) rotate(get(f) == get(x) ? f : x);
	if (!g) root = x;
}

inline int select(int k) {
	for (register int rt = root; rt;) {
		pushdown(rt);
		if (k == size[ch[rt][0]] + 1) return rt;
		if (k < size[ch[rt][0]] + 1) rt = ch[rt][0];
		else k -= size[ch[rt][0]] + 1, rt = ch[rt][1];
	}
	throw;
}
int build(int l, int r, int f) {
	if (l>r) return 0;
	int rt = create(), mid = (l + r) >> 1;
	if (l == r) {
		val[rt] = sum[rt] = ary[mid];
		size[rt] = 1;
		ch[rt][0] = ch[rt][1] = 0;
		fa[rt] = f;
		lmax[rt] = rmax[rt] = max(0ll, val[rt]);
		mmax[rt] = val[rt];
		return rt;
	}
	val[rt] = ary[mid], fa[rt] = f;
	ch[rt][0] = build(l, mid - 1, rt);
	ch[rt][1] = build(mid + 1, r, rt);
	return maintain(rt), rt;
}

inline void insert(int pos, int tot) {
	if (!tot) return;
	int l = select(pos + 1), r = select(pos + 2);
	splay(l, 0), splay(r, l);
	ch[r][0] = build(1, tot, r);
	maintain(r), maintain(l);
}

void recycle(int rt) {
	if (!rt) return;
	rec.push(rt);
	recycle(ch[rt][0]);
	recycle(ch[rt][1]);
	clear(rt);
}
inline void erase(int pos, int tot) {
	if (!tot) return;
	int l = select(pos), r = select(pos + tot + 1);
	splay(l, 0), splay(r, l);
	recycle(ch[r][0]), ch[r][0] = 0;
	maintain(r), maintain(l);
}

inline void assign(int pos, int tot, LL c) {
	if (!tot) return;
	int l = select(pos), r = select(pos + tot + 1);
	splay(l, 0), splay(r, l);
	int x = ch[r][0];
	val[x] = c, sum[x] = size[x] * c;
	if (c >= 0) lmax[x] = rmax[x] = mmax[x] = sum[x];
	else lmax[x] = rmax[x] = 0, mmax[x] = val[x];
	cov[x] = 1;
	maintain(r), maintain(l);
}

inline void reverse(int pos, int tot) {
	if (!tot) return;
	int l = select(pos), r = select(pos + tot + 1);
	splay(l, 0), splay(r, l);
	int x = ch[r][0];
	if (cov[x]) return;
	swap(ch[x][0], ch[x][1]);
	swap(lmax[x], rmax[x]);
	rev[x] ^= 1;
	maintain(r), maintain(l);
}

inline LL getSum(int pos, int tot) {
	if (!tot) return 0ll;
	int l = select(pos), r = select(pos + tot + 1);
	splay(l, 0), splay(r, l);
	return sum[ch[r][0]];
}
inline LL getMaxSum() {
	int l = select(1), r = select(size[root]);
	splay(l, 0), splay(r, l);
	return mmax[ch[r][0]];
}

void out(int rt) {
	if (!rt) return;
	pushdown(rt);
	out(ch[rt][0]);
	cout << val[rt] << ' ';
	out(ch[rt][1]);
}

signed main() {
	ios::sync_with_stdio(0);
	cin >> n >> q;
	
	for (register int i = 1; i <= n; i++)
		cin >> ary[i + 1];
	ary[1] = ary[n + 2] = -inf;
	
	clear(0);
	root = build(1, n + 2, 0);
	
	while (q--) {
		string cmd;
		int pos, tot;
		LL c;
		
		cin >> cmd;
		if (cmd == "INSERT") {
			cin >> pos >> tot;
			for (register int i = 1; i <= tot; i++)	
				cin >> ary[i];
			insert(pos, tot);
		}
		if (cmd == "DELETE") {
			cin >> pos >> tot;
			erase(pos, tot);
		}
		if (cmd == "MAKE-SAME") {
			cin >> pos >> tot >> c;
			assign(pos, tot, c);
		}
		if (cmd == "REVERSE") {
			cin >> pos >> tot;
			reverse(pos, tot);
		}
		if (cmd == "GET-SUM") {
			cin >> pos >> tot;
			cout << getSum(pos, tot) << endl;
		}
		if (cmd == "MAX-SUM")
			cout << getMaxSum() << endl;
	}
}

Guess you like

Origin www.cnblogs.com/-Wallace-/p/12670235.html