线段树(代码源)

线段树

单点修改,区间查询

线段树2 - 题目 - Daimayuan Online Judge

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q;
int a[N];
struct info
{
    //最大子段和,最大前缀和,最大后缀和,和
	ll mss, mpre, msuf, s;
	info() {}
	info(int a) : mss(a), mpre(a), msuf(a), s(a) {}
};

info operator + (const info &l, const info &r)
{
	info a;
	a.s = l.s + r.s;
	a.mpre = max(l.mpre, l.s + r.mpre);
	a.msuf = max(r.msuf, r.s + l.msuf);
	a.mss = max({l.mss, r.mss, l.msuf + r.mpre});
	return a;
}
struct Node
{
	info val;
}seg[N * 4];

void update(int u)
{
	seg[u].val = seg[u << 1].val + seg[u << 1 | 1].val;
}

void build(int u, int l, int r)
{
	if (l == r)
	{
		seg[u].val = info(a[l]);
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	update(u);
}

void modify(int u, int l, int r, int pos, int val)
{
	if (l == r)
	{
		seg[u].val = info(val);
		return;
	}
	int mid = l + r >> 1;
	if (pos <= mid)
		modify(u << 1, l, mid, pos, val);
	else
		modify(u << 1 | 1, mid + 1, r, pos, val);
	update(u);
}

info query(int u, int l, int r, int ql, int qr)
{
	if (l == ql && r == qr)
		return seg[u].val;
	int mid = l + r >> 1;
	if (qr <= mid)
		return query(u << 1, l, mid, ql, qr);
	if (ql > mid)
		return query(u << 1 | 1, mid + 1, r, ql, qr);
	return query(u << 1, l, mid, ql, mid) + query(u << 1 | 1, mid + 1, r, mid + 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 op, x, y;
		scanf("%d%d%d", &op, &x, &y);
		if (op == 1)
			modify(1, 1, n, x, y);
		else
		{
			auto ans = query(1, 1, n, x, y);
			printf("%lld\n", ans.mss);
		}
	}
	return 0;
}

区间修改,区间求和

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll a[N];
int n, q;
struct Node
{
	ll mx, add;
}seg[N * 4];

void pushup(int u)
{
	seg[u].mx = max(seg[u << 1].mx, seg[u << 1 | 1].mx);
}

void settag(int u, ll t)
{
	seg[u].mx += t;
	seg[u].add += t;
}

void pushdown(int u)
{
	if (seg[u].add)
	{
		settag(u << 1, seg[u].add);
		settag(u << 1 | 1, seg[u].add);
		seg[u].add = 0;
	}
}

void build(int u, int l, int r)
{
	if (l == r)
	{
		seg[u] = {a[l], 0};
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

void modify(int u, int l, int r, int ql, int qr, ll k)
{
	if (l == ql && r == qr)
	{
		settag(u, k);
		return;
	}
	pushdown(u);
	int mid = l + r >> 1;
	if (qr <= mid)
		modify(u << 1, l, mid, ql, qr, k);
	else if (ql > mid)
		modify(u << 1 | 1, mid + 1, r, ql, qr, k);
	else
	{
		modify(u << 1, l, mid, ql, mid, k);
		modify(u << 1 | 1, mid + 1, r, mid + 1, qr, k);
	}
	pushup(u);
}

ll query(int u, int l, int r, int ql, int qr)
{
	if (l == ql && r == qr)
		return seg[u].mx;
	pushdown(u);
	int mid = l + r >> 1;
	if (qr <= mid)
		return query(u << 1, l, mid, ql, qr);
	if (ql > mid)
		return query(u << 1 | 1, mid + 1, r, ql, qr);
	return max(query(u << 1, l, mid, ql, mid), query(u << 1 | 1, mid + 1, r, mid + 1, qr));
}
int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%lld", a + i);
	build(1, 1, n);
	while(q--)
	{
		int op;
		scanf("%d", &op);
		if (op == 1)
		{
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			modify(1, 1, n, l, r, d);
		}
		else
		{
			int l, r;
			scanf("%d%d", &l, &r);
			ll ans = query(1, 1, n, l, r);
			printf("%lld\n", ans);
		}
	}
	return 0;
}

区间加、区间乘、区间赋值,区间和

线段树打标记2 - 题目 - Daimayuan Online Judge

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
ll a[N];
int n, q;

struct tag
{
	ll mul, add;
};

tag operator + (const tag &a, const tag &b)
{
	return {a.mul * b.mul % mod, (a.add * b.mul + b.add) % mod};
}

struct Node
{
	tag t;
	ll val;
	int sz;
}seg[N * 4];

void pushup(int u)
{
	seg[u].val = (seg[u << 1].val + seg[u << 1 | 1].val) % mod;
}

void settag(int u, tag t)
{
	seg[u].t = seg[u].t + t;
	seg[u].val = (seg[u].val * t.mul + seg[u].sz * t.add) % mod;
}

void pushdown(int u)
{
	if (seg[u].t.mul != 1 || seg[u].t.add != 0)
	{
		settag(u << 1, seg[u].t);
		settag(u << 1 | 1, seg[u].t);
		seg[u].t = {1, 0};
	}
}

void build(int u, int l, int r)
{
	seg[u].sz = r - l + 1;
	seg[u].t = {1, 0};
	if (l == r)
	{
		seg[u].val = a[l];
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

void modify(int u, int l, int r, int ql, int qr, tag t)
{
	if (l == ql && r == qr)
	{
		settag(u, t);
		return;
	}
	pushdown(u);
	int mid = l + r >> 1;
	if (qr <= mid)
		modify(u << 1, l, mid, ql, qr, t);
	else if (ql > mid)
		modify(u << 1 | 1, mid + 1, r, ql, qr, t);
	else
	{
		modify(u << 1, l, mid, ql, mid, t);
		modify(u << 1 | 1, mid + 1, r, mid + 1, qr, t);
	}
	pushup(u);
}

ll query(int u, int l, int r, int ql, int qr)
{
	if (l == ql && r == qr)
		return seg[u].val;
	pushdown(u);
	int mid = l + r >> 1;
	if (qr <= mid)
		return query(u << 1, l, mid, ql, qr);
	if (ql > mid)
		return query(u << 1 | 1, mid + 1, r, ql, qr);
	return (query(u << 1, l, mid, ql, mid) + query(u << 1 | 1, mid + 1, r, mid + 1, qr)) % mod;
}
int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%lld", a + i);
	build(1, 1, n);
	while(q--)
	{
		int op;
		scanf("%d", &op);
		if (op == 1)
		{
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			modify(1, 1, n, l, r, (tag){1, d});
		}
		else if (op == 2)
		{
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			modify(1, 1, n, l, r, (tag){d, 0});
		}
		else if (op == 3)
		{
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			modify(1, 1, n, l, r, (tag){0, d});
		}
		else
		{
			int l, r;
			scanf("%d%d", &l, &r);
			ll ans = query(1, 1, n, l, r);
			printf("%lld\n", ans);
		}
	}
	return 0;
}

线段树上二分

线段树上二分 - 题目 - Daimayuan Online Judge

找到某个区间中第一个 >= d 的位置

与普通线段树不同的是当 \(l==ql,\;r==qr\) 时,并不能通过直接返回区间的信息来得到答案,要继续递归

不过接下来还是单边递归,复杂度仍为 \(O(logn)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll a[N];
int n, q;
struct Node
{
	ll mx;
}seg[N * 4];

void pushup(int u)
{
	seg[u].mx = max(seg[u << 1].mx, seg[u << 1 | 1].mx);
}


void build(int u, int l, int r)
{
	if (l == r)
	{
		seg[u].mx = a[l];
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

void modify(int u, int l, int r, int pos, int k)
{
	if (l == r)
	{
		seg[u].mx = k;
		return;
	}
	int mid = l + r >> 1;
	if (pos <= mid)
		modify(u << 1, l, mid, pos, k);
	else
		modify(u << 1 | 1, mid + 1, r, pos, k);
	pushup(u);
}

int search(int u, int l, int r, int ql, int qr, int d)
{
	//当结点区间和询问区间相同时,不能直接返回,还要递归继续找
	if (l == ql && r == qr)
	{
		if (seg[u].mx < d)
			return -1;
		if (l == r)
			return l;
		int mid = l + r >> 1;
		if (seg[u << 1].mx >= d)
			return search(u << 1, l, mid, ql, mid, d);
		return search(u << 1 | 1, mid + 1, r, mid + 1, qr, d);
	}
	int mid = l + r >> 1;
	if (qr <= mid)
		return search(u << 1, l, mid, ql, qr, d);
	if (ql > mid)
		return search(u << 1 | 1, mid + 1, r, ql, qr, d);
	int pos = search(u << 1, l, mid, ql, mid, d);
	if (pos != -1)
		return pos;
	return search(u << 1 | 1, mid + 1, r, mid + 1, qr, d);
}
int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%lld", a + i);
	build(1, 1, n);
	while(q--)
	{
		int op;
		scanf("%d", &op);
		if (op == 1)
		{
			int x, d;
			scanf("%d%d", &x, &d);
			modify(1, 1, n, x, d);
		}
		else
		{
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			ll ans = search(1, 1, n, l, r, d);
			printf("%lld\n", ans);
		}
	}
	return 0;
}
posted @ 2022-06-04 17:37  hzy0227  阅读(74)  评论(0编辑  收藏  举报