「Luogu P5586」 序列 (加强版)

Description

YGXUQU.md.png

Hint

  • (1le n,qle 3 imes 10^5)
  • (0le a_i, kle 10^9)
  • 对于 (4,5) 操作,保证 (r_1-l_1=r_2-l_2)([l_1,r_1]cap[l_2, r_2] = varnothing)
  • 数据不保证随机。

Solution

ODT 被卡了,于是考虑使用平衡树(FHQ-Treap)。

区间求和

在结点中维护一个 sum 字段,表示子树的数值之和。

区间赋值

在结点中维护一个标记 cov,如果等于 (-1) 则没有。

区间加法

在结点中维护一个标记 add,如果等于 (0) 则没有。

区间反转

同样用一个标记 rev 表示。

区间交换

将整个数列截成 ([1, l_1),[l_1,r_1],(r_1,l_2),[l_2,r_2],(r_2,n]) 五段,再把第二段,第四段交换,依次重新合并即可。

区间复制

难点。如果是朴素的 FHQ-Treap 进行复制,那么区间一大直接爆炸。

索性直接 可持久化,复制对应区间的根结点然后接上,原来的直接 throw away。

注意到空间上的问题,处理地不恰当可能会导致 MLE,于是当节点数大于某一个定值时就将当前树重构,然后把无效结点丢弃。

然后就是卡卡常就过了。细节比较多,写了一个上午。

Code

不保证这份代码的每次提交都是 AC 的。

/*
 * Author : _Wallace_
 * Source : https://www.cnblogs.com/-Wallace-/
 * Problem : Luogu P5586 序列 (加强版)
 */
#include <algorithm>
#include <cstdio>
#include <cstdlib>

using namespace std;
typedef long long llint;
const int N = 3e5 + 5;
const int mod = 1e9 + 7;

namespace fastIO_int{
	inline int get_int()
	{
		int x=0,f=1;char c=getchar();
		while(c<'0'||c>'9')
		{
			if(c=='-')f=-1;
			c=getchar();
		}
		while(c>='0'&&c<='9')
			x=x*10+c-'0',c=getchar();
		return f*x;
	}
	void put_int(int x)
	{
		if(x<0)putchar('-'),x=-x;
		if(x>9)put_int(x/10);
		putchar(x%10+'0');
	}
};

struct Node {
	int lc, rc, size;
	int sum, val, add, cov;
	bool rev;
} t[N << 7];
int total, root;

#define lc(x) t[x].lc
#define rc(x) t[x].rc
#define size(x) t[x].size
#define sum(x) t[x].sum
#define val(x) t[x].val
#define add(x) t[x].add
#define rev(x) t[x].rev
#define cov(x) t[x].cov

inline int create(int v) {
	int x = ++total;
	size(x) = 1, val(x) = sum(x) = v;
	rev(x) = false, cov(x) = -1, add(x) = 0;
	lc(x) = rc(x) = 0;
	return x;
}
inline int copy(int x) {
	int y = ++total;
	t[y] = t[x];
	return y;
}

inline void pushup(int x) {
	size(x) = size(lc(x)) + size(rc(x)) + 1;
	sum(x) = ((sum(lc(x)) + sum(rc(x))) % mod + val(x)) % mod;
}

inline void setRev(int x) {
	swap(lc(x), rc(x)), rev(x) ^= 1;
}
inline void setAdd(int x, int v) {
	sum(x) = (sum(x) + (llint)size(x) * v) % mod;
	(val(x) += v) %= mod, (add(x) += v) %= mod;
}
inline void setCov(int x, int v) {
	sum(x) = (llint)size(x) * v % mod;
	val(x) = cov(x) = v, add(x) = 0;
}
inline void pushdown(int x) {
	if (cov(x) != -1 || rev(x) || add(x)) {
		if (lc(x)) lc(x) = copy(lc(x));
		if (rc(x)) rc(x) = copy(rc(x));
	}
	if (cov(x) != -1) {
		if (lc(x)) setCov(lc(x), cov(x));
		if (rc(x)) setCov(rc(x), cov(x));
		cov(x) = -1;
	}
	if (add(x)) {
		if (lc(x)) setAdd(lc(x), add(x));
		if (rc(x)) setAdd(rc(x), add(x));
		add(x) = 0;
	}
	if (rev(x)) {
		if (lc(x)) setRev(lc(x));
		if (rc(x)) setRev(rc(x));
		rev(x) = 0;
	}
}

int merge(int u, int v) {
	if (!u || !v) return u | v;
	if (rand() % (size(u) + size(v)) < size(u)) {
		pushdown(u), u = copy(u);
		rc(u) = merge(rc(u), v);
		return pushup(u), u;
	} else {
		pushdown(v), v = copy(v);
		lc(v) = merge(u, lc(v));
		return pushup(v), v;
	}
}
void split(int x, int k, int& u, int& v) {
	if (!x) return u = v = 0, void();
	pushdown(x);
	if (size(lc(x)) < k) {
		u = copy(x);
		split(rc(u), k - size(lc(x)) - 1, rc(u), v);
		pushup(u);
	} else {
		v = copy(x);
		split(lc(v), k, u, lc(v));
		pushup(v);
	}
}

inline void reverse(int l, int r) {
	int pl, pm, pr;
	split(root, r, pl, pr);
	split(pl, l - 1, pl, pm);
	setRev(pm = copy(pm));
	root = merge(pl, merge(pm, pr));
}
inline void assign(int l, int r, int v) {
	int pl, pm, pr;
	split(root,r, pl, pr);
	split(pl, l - 1, pl, pm);
	setCov(pm = copy(pm), v);
	root = merge(pl, merge(pm, pr));
}
inline void increase(int l, int r, int v) {
	int pl, pm, pr;
	split(root,r, pl, pr);
	split(pl, l - 1, pl, pm);
	setAdd(pm = copy(pm), v);
	root = merge(pl, merge(pm, pr));
}
inline int getSum(int l, int r) {
	int pl, pm, pr;
	split(root,r, pl, pr);
	split(pl, l - 1, pl, pm);
	int ret = sum(pm);
	root = merge(pl, merge(pm, pr));
	return ret;
}
inline void swap(int l1, int r1, int l2, int r2) {
	int pl, px, pm, py, pr;
	if (l1 > l2) swap(l1, l2), swap(r1, r2);
	split(root, r2, pl, pr);
	split(pl, l2 - 1, pl, py);
	split(pl, r1, pl, pm);
	split(pl, l1 - 1, pl, px);
	pl = merge(pl, py), pr = merge(px, pr);
	root = merge(pl, merge(pm, pr));
}
inline void paste(int l1, int r1, int l2, int r2) {
	bool f = 0; int pl, px, pm, py, pr;
	if (l1 > l2) swap(l1, l2), swap(r1, r2), f = 1;
	split(root, r2, pl, pr);
	split(pl, l2 - 1, pl, py);
	split(pl, r1, pl, pm);
	split(pl, l1 - 1, pl, px);
	f ? px = copy(py) : py = copy(px);
	pl = merge(pl, px), pr = merge(py, pr);
	root = merge(pl, merge(pm, pr));
}

int build(int l, int r, int* a) {
	if (l > r) return 0;
	int mid = (l + r) >> 1, x = create(a[mid]);
	lc(x) = build(l, mid - 1, a), rc(x) = build(mid + 1, r, a);
	return pushup(x), x;
}
void scan(int x, int* a, int& p) {
	if (!x) return;
	pushdown(x);
	scan(lc(x), a, p);
	a[++p] = val(x);
	scan(rc(x), a, p);
}

int a[N], n, q;
void rebuild() {
	scan(root, a, n = 0);
	total = 0;
	root = build(1, n, a);
}

signed main() {
	srand(465125);
	using fastIO_int::get_int;
	using fastIO_int::put_int;
	
	n = get_int(), q = get_int();
	for (register int i = 1; i <= n; i++)
		a[i] = get_int();
	root = build(1, n, a);
	
	for (int last = 0; q; --q) {
		int cmd, v, l1, r1, l2, r2;
		cmd = get_int(), l1 = get_int() ^ last, r1 = get_int() ^ last;
		switch (cmd) {
			case 1 : put_int(last = getSum(l1, r1)), putchar('
'); break;
			case 2 : v = get_int() ^ last, assign(l1, r1, v); break;
			case 3 : v = get_int() ^ last, increase(l1, r1, v); break;
			case 4 : l2 = get_int() ^ last, r2 = get_int() ^ last, paste(l1, r1, l2, r2); break;
			case 5 : l2 = get_int() ^ last, r2 = get_int() ^ last, swap(l1, r1, l2, r2); break;
			case 6 : reverse(l1, r1); break;
		}
		
		if (total > 7500000) rebuild();
	}
	scan(root, a, n = 0);
	for (register int i = 1; i <= n; i++)
		put_int(a[i]), putchar(' ');
	return putchar('
'), 0;
}
原文地址:https://www.cnblogs.com/-Wallace-/p/12869486.html