[BZOJ4355] Play with sequence(线段树)

这篇博客介绍了一个关于序列操作的题目,涉及到区间赋值、区间加法后区间取最大值以及询问区间内0的个数。通过将1操作转化为区间加法和取最大值,利用吉司机线段树实现区间取最大值,并着重强调了pushdown过程中的处理,确保加法和取最大值操作的正确性,最终达到O(mlog2n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

  • 给你一个序列,有三种操作, 1 1 1是区间赋值, 2 2 2是区间加法后区间取对 0 0 0 m a x max max, 3 3 3是询问区间内 0 0 0的个数。

首先 1 1 1操作可以转化为区间加上 − i n f -inf inf后取 m a x max max,那么我们就只要维护区间加和区间取 m a x max max操作了,区间取 m a x max max操作可以用吉司机线段树来实现,这里有个比较重要的点就是加的 − i n f -inf inf不能影响到区间次小值,就是次小值要是一个更高阶的 i n f inf inf,不然会影响一些关系。

然后最主要的应该是 p u s h d o w n pushdown pushdown,先下放加法标记再下放取 m a x max max标记,注意加法标记要对取 m a x max max造成影响,取 m a x max max标记修改的时候下放加法标记,然后就没了,复杂度 O ( m l o g 2 n ) O(mlog^2n) O(mlog2n)

 
#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<algorithm>
#include<vector>
 
#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define For(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define FOR(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define debug(x) cout << #x << " = " << x << endl
#define mem(a, b) memset(a, b, sizeof(a))
#define cpy(a, b) memcpy(a, b, sizeof(a))
#define min(a, b) (a < b ? a : b)
#define max(a, b) (b < a ? a : b)
#define inf (0x3f3f3f3f)
#define INF ((ll)1e12)
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define y1 orzorz
 
typedef unsigned long long ull;
typedef unsigned int uint;
typedef long long ll;
typedef std::pair<ll, int> PLI;
typedef std::pair<int, int> PII;
typedef long double ldb;
typedef double db;
 
namespace IO {
#define getc() ((S_ == T_) && (T_ = (S_ = Ch_) + fread(Ch_, 1, Buffsize, stdin), S_ == T_) ? 0 : *S_ ++)
#define putc(x) *nowps ++ = (x)
    const uint Buffsize = 1 << 15, Output = 1 << 23;
    static char Ch_[Buffsize], *S_ = Ch_, *T_ = Ch_;
    static char Out[Output], *nowps = Out;
    inline void flush(){fwrite(Out, 1, nowps - Out, stdout); nowps = Out;}
    template<class T>inline void read(T &_) {
        _ = 0; static char __; T ___ = 1;
        for(__ = getc(); !isdigit(__); __ = getc()) if(__ == '-') ___ = -1;
        for(; isdigit(__); __ = getc()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
        _ *= ___;
    }
    template<class T>inline void write(T _, char __ = '\n') {
        if(!_) putc('0');
        if(_ < 0) putc('-'), _ = -_;
        static uint sta[111], tp;
        for(tp = 0; _; _ /= 10) sta[++ tp] = _ % 10;
        for(; tp; putc(sta[tp --] ^ 48)); putc(__);
    }
    template<class T>inline bool chkmax(T &_, T __) {return _ < __ ? _ = __, 1 : 0;}
    template<class T>inline bool chkmin(T &_, T __) {return _ > __ ? _ = __, 1 : 0;}
}
 
using namespace std;
using namespace IO;
 
const int N = 3e5 + 10;
 
int n, q;
 
int dbg;
 
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
    ll mn[N << 2], smn[N << 2], tagmax[N << 2], nmn[N << 2], add[N << 2];
 
	void pushup(int bh) {
		int lc = ls, rc = rs;
		if(mn[lc] == mn[rc]) {
			mn[bh] = mn[lc];
			nmn[bh] = nmn[lc] + nmn[rc];
			smn[bh] = min(smn[lc], smn[rc];
		}
		else {
			if(mn[lc] > mc[rc]) swap(lc, rc);
			mn[bh] = mn[lc], nmn[bh] = nmn[lc];
			smn[bh] = min(smn[lc], mn[rc]);
		}
	}

	void modifyadd(int bh, ll val) {
		if(tagmax[bh] ^ -INF) tagmax[bh] += val;
		add[bh] += val, mn[bh] += val, smn[bh] += val;
	}

	void modifymax(int bh, int l, int r, ll val) {
		if(mn[bh] >= val) return;
		if(l ^ r && add[bh]) modifyadd(ls, add[bh]), modifyadd(rs, add[bh]), add[bh] = 0;
		if(smn[bh] > val) mn[bh] = tagmax[bh] = val;
		else tagmax[bh] = -INF, modifymax(lson, val), modifymax(rson, val), pushup(bh);
	}

	void pushdown(int bh, int l, int r) {
		if(add[bh]) 
			modifyadd(ls, add[bh]), modifyadd(rs, add[bh]), add[bh] = 0;
		if(tagmax[bh] != -INF) 
			modifymax(lson, tagmax[bh]), modifymax(rson, tagmax[bh]), tagmax[bh] = -INF;
	}

	void build(int bh, int l, int r) {
		tagmax[bh] = -INF, add[bh] = 0;
		if(l == r) scanf("%lld", &mn[bh]), smn[bh] = 1e18, nmn[bh] = 1;
		else build(lson), build(rson), pushup(bh);
	}

	void updateadd(int bh, int l, int r, int x, int y, ll z) {
		if(x <= l && r <= y) modifyadd(bh, z);
		else {
			pushdown(bh, l, r);
			if(x <= mid) updateadd(lson, x, y, z);
			if(y > mid) updateadd(rson, x, y, z);
			pushup(bh);
		}
	}

	void updatemax(int bh, int l, int r, int x, int y, ll z) {
		if(x <= l && r <= y) modifymax(bh, l, r, z);
		else {
			pushdown(bh, l, r);
			if(x <= mid) updatemax(lson, x, y, z);
			if(y > mid) updatemax(rson, x, y, z);
			pushup(bh);
		}
	}

	int query(int bh, int l, int r, int x, int y) {
		if(x > r || y < l || mn[bh] != 0) return 0;
		if(x <= l && r <= y) return nmn[bh];
		pushdown(bh, l, r);
		return query(lson, x, y) + query(rson, x, y);
	}

}T;

int main() {
#ifdef ylsakioi
	file("4355");
#endif
	scanf("%d%d", &n, &q);
	T.build(1, 1, n);
	For(i, 1, q) {
		dbg = i;
		int opt, x, y, z;
		read(opt);
		if(opt == 1) {
			read(x), read(y), read(z);
			T.updateadd(1, 1, n, x, y, -INF);
			T.updatemax(1, 1, n, x, y, z);
		}
		if(opt == 2) {
			read(x), read(y), read(z);
			T.updateadd(1, 1, n, x, y, z);
			T.updatemax(1, 1, n, x, y, 0);
		}
		if(opt == 3) {
			read(x), read(y);
			write(T.query(1, 1, n, x, y));
		}
	}
	return flush(), 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值