Segment tree beats

Segment tree beats 学习笔记

似乎时间不是很够了,就学一些最常用的吧。

不过这种题真的挺锻炼码力的

Gorgeous Sequence:区间取min,区间最值

给定长为 \(n\) 的序列。要求支持三种操作:

0 l r v:区间 \(l...r\)\(v\)\(\min\)

1 l r:区间求最大值

2 l r:区间求和

\(1 \le n,m \le 10^6\)

维护最大值 \(mx\),最大值个数\(mxcnt\),次大值\(smx\)

如果 \(mx \le v\),直接返回。

否则,如果 \(smx < v < mx\),打标记。

否则,\(v \le smx\),暴力递归。

复杂度:\(O(n \log n)\)

struct Data {
	int ls, rs, mx, mxcnt, smx, tag;
	ll sum;
	Data(){ls = rs = mxcnt = sum = 0; tag = mx = smx = -1; }
	inline void clear() { ls = rs = mxcnt = sum = 0; tag = mx = smx = -1; }
}dat[NN];
#define ls(x) dat[x].ls
#define rs(x) dat[x].rs
#define mx(x) dat[x].mx
#define mxcnt(x) dat[x].mxcnt
#define smx(x) dat[x].smx
#define tag(x) dat[x].tag
#define sum(x) dat[x].sum
int ttot, root;
inline void pushup(int cur) {
	sum(cur) = sum(ls(cur)) + sum(rs(cur));
	if (mx(ls(cur)) == mx(rs(cur))) {
		mx(cur) = mx(ls(cur));
		mxcnt(cur) = mxcnt(ls(cur)) + mxcnt(rs(cur));
		smx(cur) = max(smx(ls(cur)), smx(rs(cur)));
	} else if (mx(ls(cur)) > mx(rs(cur))) {
		mx(cur) = mx(ls(cur));
		mxcnt(cur) = mxcnt(ls(cur));
		smx(cur) = max(smx(ls(cur)), mx(rs(cur)));
	} else {
		mx(cur) = mx(rs(cur));
		mxcnt(cur) = mxcnt(rs(cur));
		smx(cur) = max(smx(rs(cur)), mx(ls(cur)));
	}
}

void build(int L, int R, int &cur) {
	cur = ++ttot;
	if (L == R) {
		mx(cur) = h[L]; mxcnt(cur) = 1;
		smx(cur) = tag(cur) = -1;
		sum(cur) = h[L];
		return ;
	}
	int mid = (L + R) >> 1;
	build(L, mid, ls(cur)), build(mid + 1, R, rs(cur));
	pushup(cur);
}
inline void pusht(int cur, int v) {
	if (mx(cur) <= v)	return ;//bug
	sum(cur) += 1ll * mxcnt(cur) * (v - mx(cur));
	mx(cur) = v; tag(cur) = v;
}
inline void pushdown(int cur) {
	if (~tag(cur))//bug
		pusht(ls(cur), tag(cur)), pusht(rs(cur), tag(cur)), tag(cur) = -1;
}
void modify_min(int L, int R, int l, int r, int v, int cur) {
	if (mx(cur) <= v)	return ;
	if (l <= L && R <= r && smx(cur) < v)	return pusht(cur, v), void();
	int mid = (L + R) >> 1; pushdown(cur);
	if (l <= mid)	modify_min(L, mid, l, r, v, ls(cur));
	if (r > mid)	modify_min(mid + 1, R, l, r, v, rs(cur));
	pushup(cur);
}

Cartesian Tree : 区间加区间取 \(\min\)

(弱化版)支持区间加,区间取 \(\min\)(或者区间取 \(\max\),但只会有一种),单点插入,全局求和。

\(n \le 150000\)

离线后单点插入变为单点修改。

打标记的时候注意加法标记和 \(\min(\max)\) 标记的顺序。由于打加法标记的时候可以很方便地修改之前的 \(\min(\max)\) 标记,于是可以认为每时每刻一个点的标记都是先加法后 \(\min(\max)\) 的。注意没有 \(\min(\max)\) 标记的时候不要修改 \(\min(\max)\) 标记。

inline void pushadd(int cur, int v) {
	if (!cnt(cur))	return ;
	sum(cur) += 1ll * cnt(cur) * v;
	mx(cur) += v; smx(cur) += v; addtag(cur) += v;
	if (~mintag(cur)) mintag(cur) += v;//bug
}
inline void pushmin(int cur, int v) {
	if (!cnt(cur) || mx(cur) <= v)	return ;
	sum(cur) += 1ll * mxcnt(cur) * (v - mx(cur));
	mx(cur) = v; mintag(cur) = v;
}
inline void pushdown(int cur) {
	if (addtag(cur))
			pushadd(ls(cur), addtag(cur)), pushadd(rs(cur), addtag(cur)), addtag(cur) = 0;
	if (~mintag(cur))
		pushmin(ls(cur), mintag(cur)), pushmin(rs(cur), mintag(cur)), mintag(cur) = -1;
}

再放一个区间取 \(\max\) 的完整版:

namespace Seg_L {//max, add, pointset, getsum
	struct Data {
		int ls, rs, cnt, mn, mncnt, smn, maxtag, addtag;
		ll sum;
		Data() { ls = rs = cnt = mncnt = sum = addtag = 0; mn = smn = maxtag = inf; }
	}Dat[N << 2];
#define ls(x) Dat[x].ls
#define rs(x) Dat[x].rs
#define cnt(x) Dat[x].cnt
#define mn(x) Dat[x].mn
#define mncnt(x) Dat[x].mncnt
#define smn(x) Dat[x].smn
#define maxtag(x) Dat[x].maxtag
#define addtag(x) Dat[x].addtag
#define sum(x) Dat[x].sum
	int ttot;
	inline void pushup(int cur) {
		sum(cur) = sum(ls(cur)) + sum(rs(cur));
		cnt(cur) = cnt(ls(cur)) + cnt(rs(cur));
		if (mn(ls(cur)) == mn(rs(cur))) {
			mn(cur) = mn(ls(cur)); mncnt(cur) = mncnt(ls(cur)) + mncnt(rs(cur));
			smn(cur) = min(smn(ls(cur)), smn(rs(cur)));//bug
		} else if (mn(ls(cur)) < mn(rs(cur))) {
			mn(cur) = mn(ls(cur)), mncnt(cur) = mncnt(ls(cur));
			smn(cur) = min(smn(ls(cur)), mn(rs(cur)));
		} else {
			mn(cur) = mn(rs(cur)), mncnt(cur) = mncnt(rs(cur));
			smn(cur) = min(smn(rs(cur)), mn(ls(cur)));
		}
	}
	inline void pushadd(int cur, int v) {
		if (!cnt(cur))	return ;
		sum(cur) += 1ll * cnt(cur) * v;
		mn(cur) += v; smn(cur) += v; addtag(cur) += v;
		if (maxtag(cur) != inf) maxtag(cur) += v;//bug
	}
	inline void pushmax(int cur, int v) {
		if (!cnt(cur) || mn(cur) >= v)	return ;
		sum(cur) += 1ll * mncnt(cur) * (v - mn(cur));
		mn(cur) = v; maxtag(cur) = v;
	}
	inline void pushdown(int cur) {
		if (addtag(cur))
			pushadd(ls(cur), addtag(cur)), pushadd(rs(cur), addtag(cur)), addtag(cur) = 0;
		if (maxtag(cur) != inf)
			pushmax(ls(cur), maxtag(cur)), pushmax(rs(cur), maxtag(cur)), maxtag(cur) = inf;
	}
	void modify_max(int L, int R, int l, int r, int v, int cur) {
		if (!cur || mn(cur) >= v)	return ;
		if (l <= L && R <= r && smn(cur) > v)	return pushmax(cur, v), void();//bug
		int mid = (L + R) >> 1; pushdown(cur);
		if (l <= mid)	modify_max(L, mid, l, r, v, ls(cur));
		if (r > mid)	modify_max(mid + 1, R, l, r, v, rs(cur));
		pushup(cur);
	}
	void modify_add(int L, int R, int l, int r, int v, int cur) {
		if (!cur)	return ;
		if (l <= L && R <= r)	return pushadd(cur, v), void();
		int mid = (L + R) >> 1; pushdown(cur);
		if (l <= mid)	modify_add(L, mid, l, r, v, ls(cur));
		if (r > mid)	modify_add(mid + 1, R, l, r, v, rs(cur));
		pushup(cur);
	}
	void modify_point(int L, int R, int pos, int v, int &cur) {
		if (!cur)	cur = ++ttot;
		if (L == R)	return sum(cur) = mn(cur) = v, mncnt(cur) = 1, cnt(cur) = 1, void();
		int mid = (L + R) >> 1; pushdown(cur);
		if (pos <= mid)	modify_point(L, mid, pos, v, ls(cur));
		else	modify_point(mid + 1, R, pos, v, rs(cur));
		pushup(cur);
	}
}
posted @ 2021-01-17 22:46  JiaZP  阅读(177)  评论(0编辑  收藏  举报