前言
线段树是一个非常实用的数据结构, 并且使用频率非常高. 所有操作都能在log时间内完成, 虽然常数要比树状数组大, 但是比起很多平衡树来说常数还是小了不少. 线段树的应用范围很广, 许多操作都能够支持.
关键是, 线段树好写好调, 完全不恶心.
除非操作非常简单, 尽量不要用树状数组. 线段树虽然代码要比树状数组大但还是很好写的, 关键是线段树要比树状数组应用范围广的多. 关于区间操作尽量用线段树.
最后要注意的就是, 能用线段树的千万不要作死去手写平衡树, 尤其是splay.
下面给出Codevs两道最简单的和操作最全的线段树.
Codevs 线段树练习
最简单滴~
#include<stdio.h>
const int maxn = 1e5 + 5;
typedef long long lnt;
int n, q;
int a[maxn];
struct node
{
node *ls, *rs;
lnt sum;
inline void update()
{
sum = ls->sum + rs->sum;
}
}pool[maxn * 4], *tail = pool, *root;
node* build(int lf, int rg)
{
node* bt = ++tail;
if(lf == rg)
{
bt->sum = a[lf];
return bt;
}
int mid = (lf + rg) >> 1;
bt->ls = build(lf, mid);
bt->rs = build(mid + 1, rg);
bt->update();
return bt;
}
void modify(node* bt, int lf, int rg, int pos, int delta)
{
if(lf == rg)
{
bt->sum += delta;
return;
}
int mid = (lf + rg) >> 1;
if(pos <= mid) modify(bt->ls, lf, mid, pos, delta);
else modify(bt->rs, mid + 1, rg, pos, delta);
bt->update();
}
lnt query(node* bt, int lf, int rg, int L, int R)
{
if(L <= lf && rg <= R) return bt->sum;
int mid = (lf + rg) >> 1;
lnt rt = 0;
if(L <= mid) rt += query(bt->ls, lf, mid, L, R);
if(R > mid) rt += query(bt->rs, mid + 1, rg, L, R);
return rt;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
root = build(1, n);
scanf("%d", &q);
for (int i = 1; i <= q; ++ i)
{
int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1) modify(root, 1, n, l, r);
if(opt == 2) printf("%lld\n", query(root, 1, n, l, r));
}
}
Codevs 线段树练习5
注意逻辑关系.
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long lnt;
const int maxn = 1e5 + 5;
const lnt inf = (lnt)1 << 62;
int n, m;
lnt a[maxn];
char ss[maxn];
struct node
{
node *ls, *rs;
lnt sum, fix, cmax, cmin;
int flag;
inline void pushdown(int lf, int rg)
{
if(flag == 1)// add
{
int mid = (lf + rg) >> 1;
ls->sum += (mid - lf + 1) * fix;
rs->sum += (rg - mid) * fix;
ls->cmax += fix, rs->cmax += fix;
ls->cmin += fix, rs->cmin += fix;
if(!ls->flag) ls->flag = 1;
if(!rs->flag) rs->flag = 1;
ls->fix += fix, rs->fix += fix;
}
if(flag == 2)// val
{
int mid = (lf + rg) >> 1;
ls->sum = (mid - lf + 1) * fix;
rs->sum = (rg - mid) * fix;
ls->cmax = ls->cmin = fix;
rs->cmax = rs->cmin = fix;
ls->flag = rs->flag = 2;
ls->fix = rs->fix = fix;
}
flag = 0, fix = 0;
}
inline void update()
{
sum = ls->sum + rs->sum;
cmax = max(ls->cmax, rs->cmax);
cmin = min(ls->cmin, rs->cmin);
}
}pool[maxn * 4], *tail = pool, *root;
node* build(int lf, int rg)
{
node* bt = ++tail;
if(lf == rg)
{
bt->cmax = bt->cmin = bt->sum = a[lf];
bt->flag = bt->fix = 0;
return bt;
}
int mid = (lf + rg) >> 1;
bt->ls = build(lf, mid);
bt->rs = build(mid + 1, rg);
bt->flag = bt->fix = 0;
bt->update();
return bt;
}
void modify(node* bt, int lf, int rg, int L, int R, lnt delta, int opt)
{
if(L <= lf && rg <= R)
{
if(opt)
{
bt->flag = 2, bt->fix = delta;
bt->sum = (rg - lf + 1) * delta;
bt->cmax = bt->cmin = delta;
}
else
{
bt->fix += delta;
if(bt->flag != 2) bt->flag = 1;
bt->sum += (rg - lf + 1) * delta;
bt->cmax += delta, bt->cmin += delta;
}
return;
}
bt->pushdown(lf, rg);
int mid = (lf + rg) >> 1;
if(L <= mid) modify(bt->ls, lf, mid, L, R, delta, opt);
if(R > mid) modify(bt->rs, mid + 1, rg, L, R, delta, opt);
bt->update();
}
lnt query_sum(node* bt, int lf, int rg, int L, int R)
{
if(L <= lf && rg <= R) return bt->sum;
bt->pushdown(lf, rg);
int mid = (lf + rg) >> 1;
lnt rt = 0;
if(L <= mid) rt += query_sum(bt->ls, lf, mid, L, R);
if(R > mid) rt += query_sum(bt->rs, mid + 1, rg, L, R);
bt->update();
return rt;
}
lnt query_max(node* bt, int lf, int rg, int L, int R)
{
if(L <= lf && rg <= R) return bt->cmax;
bt->pushdown(lf, rg);
int mid = (lf + rg) >> 1;
lnt rt1 = 0, rt2 = 0;
if(L <= mid) rt1 = query_max(bt->ls, lf, mid, L, R);
if(R > mid) rt2 = query_max(bt->rs, mid + 1, rg, L, R);
bt->update();
return max(rt1, rt2);
}
lnt query_min(node* bt, int lf, int rg, int L, int R)
{
if(L <= lf && rg <= R) return bt->cmin;
bt->pushdown(lf, rg);
int mid = (lf + rg) >> 1;
lnt rt1 = inf, rt2 = inf;
if(L <= mid) rt1 = query_min(bt->ls, lf, mid, L, R);
if(R > mid) rt2 = query_min(bt->rs, mid + 1, rg, L, R);
bt->update();
return min(rt1, rt2);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i) scanf("%lld", &a[i]);
root = build(1, n);
for (int i = 1; i <= m; ++ i)
{
scanf("%s", ss);
int l, r; lnt val;
scanf("%d%d", &l, &r);
if(ss[0] == 'a')
{
scanf("%lld", &val);
modify(root, 1, n, l, r, val, 0);
}
if(ss[0] == 's' && ss[1] == 'e')
{
scanf("%lld", &val);
modify(root, 1, n, l, r, val, 1);
}
if(ss[0] == 's' && ss[1] == 'u') printf("%lld\n", query_sum(root, 1, n, l, r));
if(ss[0] == 'm' && ss[1] == 'a') printf("%lld\n", query_max(root, 1, n, l, r));
if(ss[0] == 'm' && ss[1] == 'i') printf("%lld\n", query_min(root, 1, n, l, r));
}
}