线段树__

目录

单点修改+区间查询

线段树1(最小值+出现次数)

线段树2(最大子段和)

区间修改+区间查询

线段树打标记1(最大值)

线段树打标记2(子段和取mod)


单点修改+区间查询

线段树1(最小值+出现次数)

题解:

       需使用数据用 info 封装起来,便于修改维护,运算符 + 重载

        seg[N]记录路线段树节点

        update(id):id编号的子树发生了变化,所以更新id这个节点的信息,build 和 change 中需要                             update 向上更新(建完左右子树后)

        change:单点修改 a[pos]->val

        query:[ l , r ]区间查询

        根据需要修改info,+,update,build和change中队seg[id]

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2e5+5;
int n, q, a[N];
struct info {
	int minv, mincut;
};
info operator+(const info& a, const info& b) {
	info x;
	if (a.minv < b.minv)x = a;
	else if (b.minv < a.minv)x = b;
	else x.minv = a.minv, x.mincut = a.mincut + b.mincut;
	return x;
}
struct node {
	info val;
}seg[N * 4];

void update(int id) {//向上更新
	seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}
void build(int id, int l, int r) {//建树
	if (l == r) {
		seg[id] = { a[l],1 };
		return;
	}int m = (l + r) / 2;
	build(lson);
	build(rson);
	update(id);//!
}
void change(int id, int l, int r, int pos, int val) {//单点修改
	if (l == r) {
		seg[id].val = {val,1};
		return;
	}
	int m = (l + r) / 2;
	if (pos<=m) change(lson, pos, val);
	else change(rson, pos, val);
	update(id);//!
}
info query(int id, int l, int r, int ql, int qr) {//区间查询
	if (ql == l && qr == r) {
		return seg[id].val;
	}int m = (l + r) / 2;
	if (qr <= m)return query(lson, ql, qr);
	else if (ql > m)return query(rson, ql, qr);
	else return query(lson, ql, m) 
		+ query(rson, m+1, qr);
}

int main() {
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	build(1, 1, n);
	while (q--) {
		int tx; scanf("%d", &tx);
		if (tx == 1) {
			int x, d; scanf("%d%d", &x, &d);
			change(1, 1, n, x, d);
		}
		else {
			int l, r; scanf("%d%d", &l, &r);
			info ans = query(1, 1, n, l, r);
			printf("%d %d\n", ans.minv, ans.mincut);
		}
	}
	return 0;
}

线段树2(最大子段和)

题解:

        a[ i ]可能为负数,则区间前缀和或后缀和可能大于区间总和

        mss: max segment sum //区间最大子段和

        mpre  :  max prefix //最大前缀和

        msuf  :  max sufix //最大后缀和

        s  : sum //区间和(此题未用到)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2e5 + 5;
int n, q, a[N];
struct info {
    ll mss, mpre, msuf, s;
    info() {}
    info(int val) :mss(val), mpre(val), msuf(val), s(val) {}
};
info operator + (const info& l, const info& r) {
    info a;
    a.mss = max({ l.mss, r.mss, l.msuf + r.mpre });
    a.mpre = max(l.mpre, l.s + r.mpre);
    a.msuf = max(r.msuf, r.s + l.msuf);
    a.s = l.s + r.s;
    return a;
}
struct node {
    info val;
}seg[N * 4];

void update(int id) {
    seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}
void build(int id, int l, int r) {
    if (l == r) {
        seg[id].val = info(a[l]);
        return;
    }
    int m = (l + r) / 2;
    build(lson);
    build(rson);
    update(id);//!
}

void change(int id, int l, int r, int pos, int val) {
    if (l == r) {
        seg[id].val = info(val);
        return;
    }
    int m = (l + r) / 2;
    if (pos <= m) change(lson, pos, val);
    else change(rson, pos, val);
    update(id);//!
}

info query(int id, int l, int r, int ql, int qr) {
    if (ql == l && qr == r) {
        return seg[id].val;
    }
    int m = (l + r) / 2;
    if (qr <= m) return query(lson, ql, qr);
    else if (ql > m) return query(rson, ql, qr);
    else return query(lson, ql, m) +
        query(rson, m + 1, qr);
}
int main() {
    scanf("%d %d", &n, &q);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    build(1, 1, n);
    while (q--) {
        int ty; scanf("%d", &ty);
        if (ty == 1) {
            int pos, val; scanf("%d %d", &pos, &val);
            change(1, 1, n, pos, val);
        }
        else {
            int l, r; scanf("%d %d", &l, &r);
            info ans = query(1, 1, n, l, r);
            printf("%lld\n", ans.mss);
        }
    }
    return 0;
}

区间修改+区间查询

线段树打标记1(最大值)

题解:

        settag(id):给id这个节点打标记,同时节点的信息发生变化

         update(id):id编号的子树发生了变化,所以更新id这个节点的信息,build 和 modify 中需要                             update 向上更新(建完左右子树后)

        pushdown(id):将id节点的标记下传给子节点,区间修改 modify 和区间查询 query 中传递到                              子节点前进行

        modify:[ l , r ]区间修改

注意tag要开ll ,因为标记可能叠加(不着急传到子节点)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2e5 + 5;
int n, q, a[N];
struct node {
    ll t, val;
}seg[N * 4];

void update(int id) {
    seg[id].val = max(seg[id * 2].val , seg[id * 2 + 1].val);
}
void settag(int id, ll t) {
    seg[id].val += t;
    seg[id].t += t;
}
void pushdown(int id) {
    if (seg[id].t) {
        settag(id * 2, seg[id].t);
        settag(id * 2 + 1, seg[id].t);
        seg[id].t = 0;
    }
}
void build(int id, int l, int r) {
    if (l == r) {
        seg[id].val = a[l];
        return;
    }
    int m = (l + r) / 2;
    build(lson);
    build(rson);
    update(id);//!
}

void modify(int id, int l, int r, int ql, int qr,int t) {
    if (ql==l&&qr == r) {
        settag(id, t);
        return;
    }pushdown(id);
    int m = (l + r) / 2;
    if (qr <= m) modify(lson, ql, qr, t);
    else if (ql > m)modify(rson, ql, qr, t);
    else modify(lson, ql, m, t), 
        modify(rson, m + 1, qr, t);
    update(id);//!
}

ll query(int id, int l, int r, int ql, int qr) {
    if (ql == l && qr == r) {
        return seg[id].val;
    }pushdown(id);
    int m = (l + r) / 2;
    if (qr <= m) return query(lson, ql, qr);
    else if (ql > m) return query(rson, ql, qr);
    else return max(query(lson, ql, m) ,
        query(rson, m + 1, qr));
    //update(id);
}
int main() {
    scanf("%d %d", &n, &q);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    build(1, 1, n);
    while (q--) {
        int ty; scanf("%d", &ty);
        if (ty == 1) {
            int l, r, t; 
            scanf("%d%d%d", &l, &r, &t);
            modify(1, 1, n, l, r, t);
        }
        else {
            int l, r; scanf("%d%d", &l, &r);
            ll ans=query(1, 1, n, l, r);
            printf("%lld\n", ans);
        }
    }
    return 0;
}

线段树打标记2(子段和取mod)

题解:  

按常理来说,要有多个标记。但是多个标记太麻烦了,而且还要考虑先后顺序。所以就萌发出一种合并这3个标记的想法,在根据合并后的标记对区间和进行更新

struct tag { ll mul, add; };

  • +d  -> v*1+d   {1,d}
  • *d  -> v*d+0   {d,0}
  • 变成d -> v*0+d  {0, d}    

起始时,tag的每个tag的初始状态为(1,0),即v*1+0

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson id*2,l,m
#define rson id*2+1,m+1,r
const int N = 2E5 + 5;
int n, q, a[N];
const int mod = 1e9 + 7;

struct tag {
	ll mul, add;
};
tag operator + (const tag& t1, const tag& t2) {
	// (mul1 + add1) * mul2 + add2;
	return { t1.mul * t2.mul % mod, (t1.add * t2.mul % mod + t2.add) % mod };
}
struct node {
	tag t;
	ll val;
	int sz;
}seg[N * 4];


void update(int id) {
	seg[id].val = (seg[id * 2].val + seg[id * 2 + 1].val) % mod;
}
void build(int id, int l, int r) {
	seg[id].t = (tag){ 1, 0 };
	seg[id].sz = r - l + 1;
	if (l == r) {
		seg[id].val = a[l];
	}
	else {
		int m = (l + r) / 2;
		build(lson);
		build(rson);
		update(id);
	}
}
void settag(int id, tag t) {
	seg[id].val = seg[id].val * t.mul % mod + seg[id].sz * t.add % mod;
	seg[id].t = seg[id].t + t;
}

void pushdown(int id) {
	if (seg[id].t.mul != 1 || seg[id].t.add != 0) {
		settag(id * 2, seg[id].t);
		settag(id * 2 + 1, seg[id].t);
		seg[id].t.mul = 1;
		seg[id].t.add = 0;
	}
}
void modify(int id, int l, int r, int ql, int qr, tag t) {
	if (l == ql && r == qr) {
		settag(id, t);
		return;
	}
	pushdown(id);
	int m = (l + r) / 2;
	if (qr <= m) modify(lson, ql, qr, t);
	else if (ql > m) modify(rson, ql, qr, t);
	else modify(lson, ql, m, t),
		modify(rson,  m + 1, qr, t);
	update(id);
}

ll query(int id, int l, int r, int ql, int qr) {
	if (l == ql && r == qr) {
		return seg[id].val;
	}
	pushdown(id);
	int m = (l + r) / 2;
	if (qr <= m) return query(lson, ql, qr);
	else if (ql > m) return query(rson, ql, qr);
	else return (query(lson, ql, m) +
		query(rson, m + 1, qr)) % mod;
}
int main() {
	scanf("%d %d", &n, &q);
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	build(1, 1, n);
	while (q--) {
		int ty; scanf("%d", &ty);
		if (ty <= 3) {
			int l, r, d;
			scanf("%d %d %d", &l, &r, &d);
			if (ty == 1) modify(1, 1, n, l, r, (tag) { 1, d });
			else if (ty == 2) modify(1, 1, n, l, r, (tag) { d, 0 });
			else modify(1, 1, n, l, r, (tag) { 0, d });
		}
		else {
			int l, r; scanf("%d %d", &l, &r);
			printf("%lld\n", query(1, 1, n, l, r));
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值