模板分享:线段树(1)

Code

先放代码

template<class Info>
struct segment{
private:
	#define ls (u * 2 + 1)
	#define rs (u * 2 + 2)
	
	struct Node{
		int l, r;
		Info info;
	};
	vector<Node> tr;

public:
    using info_type = Info;
	segment() {}
	segment(int n, Info v = Info()){
		vector<Info> a(n, v);
		init(a);
	}
	template<class T>
	segment(const vector<T> &a){
		init(a);
	}
	
	template<class T>
	void init(const vector<T> &a){
		int n = a.size();
		tr.resize(n << 2);
		build(0, 0, n - 1, a);
	}

private:
	void pushup(int u){
		tr[u].info = tr[ls].info + tr[rs].info;
	}
	
	template<class T>
	void build(int u, int l, int r, const vector<T> &a){
		tr[u].l = l;
		tr[u].r = r;
		if(l == r){
			tr[u].info = a[l];
			return;
		}
		int mid = (l + r) >> 1;
		build(ls, l, mid, a);
		build(rs, mid + 1, r, a);
		pushup(u);
	}
	
	void modify(int u, int x, const Info &v){
		if(tr[u].l == tr[u].r){
			tr[u].info = v;
			return;
		}
		
		int mid = tr[u].l + tr[u].r >> 1;
		if(x <= mid) modify(ls, x, v);
		else modify(rs, x, v);
		pushup(u);
	}
	
	void add(int u, int x, const Info &v){
		if(tr[u].l == tr[u].r){
			tr[u].info = tr[u].info + v;
			return;
		}
		
		int mid = tr[u].l + tr[u].r >> 1;
		if(x <= mid) add(ls, x, v);
		else add(rs, x, v);
		pushup(u);
	}
	
	Info query(int u, int l, int r){
		if(l <= tr[u].l && r >= tr[u].r) return tr[u].info;
		
		int mid = tr[u].l + tr[u].r >> 1;
		if(r <= mid) return query(ls, l, r);
		if(l > mid) return query(rs, l, r);
		return query(ls, l, r) + query(rs, l, r);
	}
	
	Info get(int u, int x){
		if(tr[u].l == tr[u].r) return tr[u].info;
		int mid = tr[u].l + tr[u].r >> 1;
		if(x <= mid) return get(ls, x);
		else return get(rs, x);
	}

public:
	void modify(int x, const Info &v){
		modify(0, x, v);
	}
	
	void add(int x, const Info &v){
		add(0, x, v);
	}
	
	Info query(int l, int r){
		return query(0, l, r);
	}
	
	Info get(int x){
		return get(0, x);
	}
	
	#undef ls
	#undef rs
};

Initialize

segment<Info>(int n, Info v = Info());

初始化大小为 n n n 的线段树,每一项为 v v v.
1 ≤ n ≤ 1 0 7 1 \le n \le 10^7 1n107

segment<Info>(const vector<T> &a);

使用 a a a 初始化大小为 ∣ a ∣ |a| a 的线段树.
1 ≤ ∣ a ∣ ≤ 1 0 7 1 \le |a| \le 10^7 1a107

其中 Info \texttt{Info} Info 类需要支持 + + +(合并信息)操作.

Modify

void segment<Info>::modify(int x, const Info &v);

执行 a x ← v a_x \gets v axv
0 ≤ x < n 0 \le x < n 0x<n

void segment<Info>::add(int x, const Info &v);

执行 a x ← a x + v a_x \gets a_x+v axax+v
0 ≤ x < n 0 \le x < n 0x<n

Query

Info segment<Info>::query(int l, int r);

a l + a l + 1 + ⋯ + a r a_l+a_l+1+\cdots+a_r al+al+1++ar.
0 ≤ l ≤ r < n 0 \le l \le r < n 0lr<n

Info segment<Info>::get(int x);

获得 a x a_x ax 的值。
0 ≤ x < n 0 \le x < n 0x<n

Example

给定序列 a = ( a 1 , a 2 , ⋯   , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an),有 m m m 个操作分两种:

  • set ⁡ ( p , v ) \operatorname{set}(p,v) set(p,v):执行 a p = v a_p=v ap=v.
  • query ⁡ ( l , r ) \operatorname{query}(l,r) query(l,r):求 max ⁡ [ u , v ] ∈ [ l , r ] ( ∑ i = u v a i ) \max\limits_{[u,v] \in [l,r]} (\sum\limits_{i=u}^v a_i) [u,v][l,r]max(i=uvai).
int max(int a, int b, int c) { return max(a, max(b, c)); }

struct Info {
	int sum, lmax, rmax, ans;
	Info(int _sum = 0, int _lmax = 0, int _rmax = 0, int _ans = 0):
		sum(_sum), lmax(_lmax), rmax(_rmax), ans(_ans) {}
};

Info operator+(const Info &lhs, const Info &rhs) {
	Info res;
	res.sum = lhs.sum + rhs.sum;
	res.lmax = max(lhs.lmax, lhs.sum + rhs.lmax);
	res.rmax = max(rhs.rmax, lhs.rmax + rhs.sum);
	res.ans = max(lhs.ans, rhs.ans, lhs.rmax + rhs.lmax);
	return res;
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	cin >> n >> m;
	
	vector<Info> info(n);
	for (int i = 0, x; i < n; i++) {
		cin >> x;
		info[i] = Info(x, x, x, x);
	}
	
	segment<Info> seg(info);
	for (int i = 0, op, x, y; i < m; i++) {
		cin >> op >> x >> y;
		if (op == 1) {
		    x--, y--;
			if (x > y) swap(x, y);
			cout << seg.query(x, y).ans << endl;
		}
		else {
		    x--;
		    seg.modify(x, Info(y, y, y, y));
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值