专题1.5 - 写个线段树板子
线段树什么功能就不需要多说了,这边主要是讲讲(lazy)标记的作用。
普通的线段树,修改的效率为(Omicron(nlog n)),查询效率为(Omicron(nlog n)),修改的效率甚至比直接修改还慢(当然直接修改就没法维护线段树了),那么怎么可以提高修改的效率?
这里需要引入(lazy)标记的概念,具体原理如下:
1.修改时,如果修改范围恰好为当前区间范围,停止向下搜索,打上(lazy)标记。
2.修改时,如果范围并非恰好,需要向下传递一次(lazy)标记。
3.查询时,优先向下传递(lazy)标记。
这边给出两个模板:
洛谷P3372
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define ppb pop_back
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
const int maxn = 1e5 + 10;
int n, m;
ll tmp[maxn], a[4 * maxn], lazy[4 * maxn];
using namespace std;
void build(int o, int l, int r)
{
if (l == r)
{
a[o] = tmp[l];
return;
}
int mid = (l + r) / 2;
int ls = 2 * o;
int rs = 2 * o + 1;
build(ls, l, mid);
build(rs, mid + 1, r);
a[o] = a[ls] + a[rs];
}
void pushdown(int o, int l, int r)
{
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
lazy[ls] += lazy[o];
lazy[rs] += lazy[o];
a[ls] += (mid - l + 1) * lazy[o];
a[rs] += (r - mid) * lazy[o];
lazy[o] = 0;
}
void Update(int o, int l, int r, int ql, int qr, int d)
{
if (l == ql && r == qr)
{
a[o] += (r - l + 1) * d;
lazy[o] += d;
return;
}
pushdown(o, l, r);
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
if (mid >= qr)
Update(ls, l, mid, ql, qr, d);
else if (mid < ql)
Update(rs, mid + 1, r, ql, qr, d);
else
{
Update(ls, l, mid, ql, mid, d);
Update(rs, mid + 1, r, mid + 1, qr, d);
}
a[o] = a[ls] + a[rs];
}
ll Query(int o, int l, int r, int ql, int qr)
{
if (l == ql && r == qr)
return a[o];
pushdown(o, l, r);
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
if (mid >= qr)
return Query(ls, l, mid, ql, qr);
else if (mid < ql)
return Query(rs, mid + 1, r, ql, qr);
else
{
return Query(ls, l, mid, ql, mid) + Query(rs, mid + 1, r, mid + 1, qr);
}
}
int main()
{
fast;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> tmp[i];
}
build(1, 1, n);
int opt;
while (m--)
{
cin >> opt;
if (opt == 1)
{
int l, r, d;
cin >> l >> r >> d;
Update(1, 1, n, l, r, d);
}
else
{
int l, r;
cin >> l >> r;
cout << Query(1, 1, n, l, r) << '
';
}
}
}
洛谷P3373
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define ppb pop_back
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
const int maxn = 1e5 + 10;
int p;
int n, m;
ll tmp[maxn], a[4 * maxn], add[4 * maxn], mul[4 * maxn];
using namespace std;
void build(int o, int l, int r)
{
if (l == r)
{
a[o] = tmp[l];
return;
}
int mid = (l + r) / 2;
int ls = 2 * o;
int rs = 2 * o + 1;
build(ls, l, mid);
build(rs, mid + 1, r);
a[o] = a[ls] + a[rs];
}
void pushdown(int o, int l, int r)
{
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
mul[ls] = mul[ls] * mul[o] % p;
mul[rs] = mul[rs] * mul[o] % p;
add[ls] = (add[ls] * mul[o] + add[o]) % p;
add[rs] = (add[rs] * mul[o] + add[o]) % p;
a[ls] = (a[ls] * mul[o] + add[o] * (mid - l + 1)) % p;
a[rs] = (a[rs] * mul[o] + add[o] * (r - mid)) % p;
add[o] = 0;
mul[o] = 1;
}
void Update_mul(int o, int l, int r, int ql, int qr, int d)
{
if (l == ql && r == qr)
{
a[o] = a[o] * d % p;
mul[o] = mul[o] * d % p;
add[o] = add[o] * d % p;
return;
}
pushdown(o, l, r);
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
if (mid >= qr)
Update_mul(ls, l, mid, ql, qr, d);
else if (mid < ql)
Update_mul(rs, mid + 1, r, ql, qr, d);
else
{
Update_mul(ls, l, mid, ql, mid, d);
Update_mul(rs, mid + 1, r, mid + 1, qr, d);
}
a[o] = (a[ls] + a[rs]) % p;
}
void Update_add(int o, int l, int r, int ql, int qr, int d)
{
if (l == ql && r == qr)
{
a[o] += (r - l + 1) * d;
add[o] += d;
return;
}
pushdown(o, l, r);
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
if (mid >= qr)
Update_add(ls, l, mid, ql, qr, d);
else if (mid < ql)
Update_add(rs, mid + 1, r, ql, qr, d);
else
{
Update_add(ls, l, mid, ql, mid, d);
Update_add(rs, mid + 1, r, mid + 1, qr, d);
}
a[o] = (a[ls] + a[rs]) % p;
}
ll Query(int o, int l, int r, int ql, int qr)
{
if (l == ql && r == qr)
return a[o] % p;
pushdown(o, l, r);
int mid = (l + r) / 2;
int ls = 2 * o, rs = 2 * o + 1;
if (mid >= qr)
return Query(ls, l, mid, ql, qr) % p;
else if (mid < ql)
return Query(rs, mid + 1, r, ql, qr) % p;
else
{
return (Query(ls, l, mid, ql, mid) + Query(rs, mid + 1, r, mid + 1, qr)) % p;
}
}
int main()
{
fast;
cin >> n >> m >> p;
for (int i = 1; i <= n; i++)
{
cin >> tmp[i];
}
build(1, 1, n);
for (int i = 1; i <= 4 * n; i++)
{
add[i] = 0;
mul[i] = 1;
}
int opt;
while (m--)
{
cin >> opt;
if (opt == 1)
{
int l, r, d;
cin >> l >> r >> d;
Update_mul(1, 1, n, l, r, d);
}
else if (opt == 2)
{
int l, r, d;
cin >> l >> r >> d;
Update_add(1, 1, n, l, r, d);
}
else
{
int l, r;
cin >> l >> r;
cout << Query(1, 1, n, l, r) << '
';
}
}
}
值得注意的是,需要注意向下传递(lazy)的顺序,以及对结果的影响。