线段树(代码源)
线段树
单点修改,区间查询
线段树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;
}