[UOJ164] 【清華集訓2015】V(線段樹)

題意

  • 給你一個序列,支持區間加上一個數,區間減去一個數,區間賦值,單點查詢,單點歷史最大值查詢。

首先發現三種操作可以轉化爲同樣的形式,定義(x,y)(x,y)爲區間加上xx後與yy取max的標記,那麼區間加就是(x,0)(x, 0),區間減就是(x,0)(-x, 0),區間賦值就是(inf,x)(-inf,x),這個標記合併也比較方便,在(a,b)(a,b)標記後加上(c,d)(c,d)這個標記就變成了(a+c,max(b+c,d))(a+c,max(b+c,d))

這樣子我們就能很方便實現單點查詢了,但是單點歷史最大值查詢似乎不太好做,我們對於每個點維護一個歷史最大值標記,分別表示作用在這上面的所有標記中的兩維分別的歷史最大值,意思就是兩維並不需要在同一個時候打上這個標記,下放的時候把父親的歷史最大值標記直接給兒子就好了,因爲在下放前的所有影響了父親的標記一定會影響兒子,並且這些標記是在兒子標記確定好之後發生的,所以可以直接把歷史最大值標記合併到兒子的當前標記上,複雜度O(n log n)O(\text{n log n})

#include <bits/stdc++.h>

#define x first
#define y second
#define pb push_back
#define mp make_pair
#define inf (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof(a))
#define Rep(i, a) for (int i = 0; i < a; ++ i)
#define For(i, a, b) for (int i = a; i <= b; ++ i)
#define FOR(i, a, b) for (int i = a; i >= b; -- i)

using namespace std;

typedef long long ll;
typedef pair<ll, ll> PLL;

template<class T>inline T read(T &_) {
	T __ = getchar(), ___ = 1; _ = 0;
	for (; !isdigit(__); __ = getchar()) if (__ == '-') ___ = -1;
	for (; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
	return _ *= ___;
}

template<class T>inline bool chkmax(T &_, T __) { return _ < __ ? _ = __, 1 : 0; }
template<class T>inline bool chkmin(T &_, T __) { return _ > __ ? _ = __, 1 : 0; }

inline void proStatus() {
	ifstream t("/proc/self/status");
	cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}

const ll INF = 1e18;
const int N = 5e5 + 7;

inline PLL Max(PLL x, PLL y) { return mp(max(x.x, y.x), max(x.y, y.y)); } 
inline PLL Merge(PLL x, PLL y) { return mp(max(-INF, x.x + y.x), max(x.y + y.x, y.y)); }
inline void Chkmax(PLL &x, PLL y) { x = Max(x, y); }

struct Segment_Tree {
#define ls (bh << 1)
#define rs (ls | 1)
#define mid ((l + r) >> 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r

	int tag[N << 2]; 
	PLL now[N << 2], his[N << 2]; 

	void build(int bh, int l, int r) {
		if (l ^ r) build(lson), build(rson);
		else his[bh].x = read(now[bh].x);
	}

	void pushdown(int bh) {
		for (int son = ls; son <= rs; ++ son) {
			tag[son] = true;
			his[son] = Max(his[son], Merge(now[son], his[bh]));
			now[son] = Merge(now[son], now[bh]);
		}
		now[bh] = his[bh] = mp(0, tag[bh] = 0);
	}

	void update(int bh, int l, int r, int x, int y, PLL z) {
		if (x <= l && r <= y) {
			Chkmax(his[bh], now[bh] = Merge(now[bh], z));
			tag[bh] = true;
		}
		else {
			if (tag[bh]) pushdown(bh);
			if (x <= mid) update(lson, x, y, z);
			if (y > mid) update(rson, x, y, z);
		}
	}

	int query(int bh, int l, int r, int x) {
		if (l == r) return bh;
		if (tag[bh]) pushdown(bh);
		return x <= mid ? query(lson, x) : query(rson, x);
	}

}T;

int main() {
#ifndef ONLINE_JUDGE
	freopen("164.in", "r", stdin);
	freopen("164.out", "w", stdout);
#endif

	int n, m, opt, x, y, z; 

	read(n), read(m), T.build(1, 1, n);
	For(i, 1, m) {
		read(opt), read(x);
		if (opt < 4) {
			read(y), read(z);
			if (opt == 1) T.update(1, 1, n, x, y, mp(z, 0));
			if (opt == 2) T.update(1, 1, n, x, y, mp(-z, 0));
			if (opt == 3) T.update(1, 1, n, x, y, mp(-INF, z));
		}
		else {
			int bh = T.query(1, 1, n, x);
			printf("%lld\n", opt < 5 ? max(T.now[bh].x, T.now[bh].y) 
					: max(T.his[bh].x, T.his[bh].y));
		}
	}

	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章