线段树
来源:互联网 发布:淘宝衣服能买吗 编辑:程序博客网 时间:2024/06/05 03:48
线段树
简介
线段树是一棵二叉树,树中的每一个结点表示了一个区间[a,b]。每一个叶子节点表示了一个单位区间。对于每一个非叶结点所表示的结点[a,b],其左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b]。线段树需要注意的几点
1、线段树空间一般要开到数据规模的4~5倍(不卡数据尽可能多开)
2、lson、rson几个变量尽可能位运算吧(省时),想偷懒就用#define 好了
3、build函数(下文会介绍)中,if (l == r) sum[n] = a[l] 或sum[n] = a[r]注意不是sum[n] = a[n]
4、下文几个常用函数中,标记‘*’的可根据需要修改- 几个线段树的常用函数
//build(建树用)函数的伪代码 /build (int n, int l, int r){ size[n] = r - l + 1; if (l == r){ sum[n] = a[l]; return ; } int mid = (l + r) >> 1; build (n << 1, l, mid); build (n << 1 | 1, mid + 1, r); sum[n] = sum[n << 1] + sum[n << 1 | 1];//*}//updata (区间修改)伪代码/down (int n){ sum[n << 1] += lazy[n] * size[n << 1]; sum[n << 1 | 1] += lazy[n] * size[n << 1 | 1];//* /上述两步是区间求和的代码 求最大值应为 sum[n << 1] += lazy[n]; sum[n << 1 | 1] += lazy[n];/ lazy[n << 1] += lazy[n], lazy[n << 1 | 1] += lazy[n], lazy[n] = 0;}updata (int n, int l, int r, int xl, int xr, int v){ if (l != r) down(n);/即在解决单点修改问题 --> 单点不需要down/ if (l == xl && r == xr){ sum[n] += v * size[n], lazy[n] += v;//* return ; } int mid = (l + r) >> 1; if (xr <= mid) updata(n << 1, l, mid, xl, xr, v); else if (xl > mid) updata(n << 1 | 1, mid + 1, r, xl, xr, v); else updata(n << 1, l, mid, xl, mid, v), updata(n << 1 | 1, mid + 1, r, mid + 1, xr, v); sum[n] = sum[n << 1] + sum[n << 1 | 1];//*}//query (区间查询“sum”函数)伪代码 /int query (int n, int l, int r, int xl, int xr){ if (l != r) down(n); if (xl <= l && r <= xr) return sum[n]; int mid = (l + r) >> 1; if (xr <= mid) return query(n << 1, l, mid, xl, xr); else if (xl > mid) return query(n << 1 | 1, mid + 1, r, xl, xr); else return query(n << 1, l, mid, xl, mid) + query(n << 1 | 1, mid + 1, r, mid + 1, xr);}
- 下面看几道例题(题目差不多)
Codevs 1080线段树练习
#include <iostream>#include <cstdio>#include <cstdlib>#define ls (n << 1)#define rs (n << 1 | 1)using namespace std;int num, m, bj;int a[1000100];int size[1000100];int lazy[1000100];int sum[1000100];int n, v, xl, xr;void build(int n, int l, int r){ size[n] = r - l + 1; if (l == r){ sum[n] = a[l]; return ; } int mid = (l + r) >> 1; build(ls, l, mid), build(rs, mid + 1, r); sum[n] = sum[ls] + sum[rs];}void down(int n){ sum[ls] += lazy[n] * size[ls]; sum[rs] += lazy[n] * size[rs]; lazy[ls] += lazy[n], lazy[rs] += lazy[n], lazy[n] = 0;}void add(int n, int l, int r, int xl, int xr, int v){ if (l != r) down(n); if (xl == l && r == xr){ sum[n] += v * size[n]; lazy[n] += v; return ; } int mid = (l + r) >> 1; if (xr <= mid) add(ls, l, mid, xl, xr, v); else if (xl > mid) add(rs, mid + 1, r, xl, xr, v); else add(ls, l, mid, xl, mid, v), add(rs, mid + 1, r, mid + 1, xr, v); sum[n] = sum[ls] + sum[rs];}int query(int n, int l, int r, int xl, int xr){ if (l != r) down(n); if (xl <= l && r <= xr) return sum[n]; int mid = (l + r) >> 1; if (xr <= mid) return query(ls, l, mid, xl, xr); else if (xl > mid) return query(rs, mid + 1, r, xl, xr); else return query(ls, l, mid, xl, mid) + query(rs, mid + 1, r, mid + 1, xr);}int main(){ scanf("%d", &num); for (int i = 1; i <= num; ++i) scanf("%d", &a[i]); build(1, 1, num); scanf("%d", &m); for (int i = 1; i <= m; ++i){ scanf("%d", &bj); if (bj == 1) scanf("%d %d", &n, &v), add(1, 1, num, n, n, v); else scanf("%d %d", &xl, &xr), printf("%d\n", query(1, 1, num, xl, xr)); } return 0;}
Codevs 1081线段树练习2
#include <iostream>#include <cstdio>#include <cstdlib>#define ls (n << 1)#define rs (n << 1 | 1)#define L 500000using namespace std;int num, m, bj;int a[L];int size[L];int lazy[L];int sum[L];int n, v, l, r, j;int gi(){ char cj = getchar(); int ans = 0; while (cj > '9' || cj < '0') cj = getchar(); while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar(); return ans;}void build(int n, int l, int r){ size[n] = r - l + 1; if (l == r){ sum[n] = a[l]; return ; } int mid = (l + r) >> 1; build(ls, l, mid), build(rs, mid + 1, r); sum[n] = sum[ls] + sum[rs];}void down(int n){ sum[ls] += lazy[n] * size[ls]; sum[rs] += lazy[n] * size[rs]; lazy[ls] += lazy[n], lazy[rs] += lazy[n], lazy[n] = 0;}void add(int n, int l, int r, int xl, int xr, int v){ if (l != r) down(n); if (xl == l && r == xr){ sum[n] += v * size[n]; lazy[n] += v; return ; } int mid = (l + r) >> 1; if (xr <= mid) add(ls, l, mid, xl, xr, v); else if (xl > mid) add(rs, mid + 1, r, xl, xr, v); else add(ls, l, mid, xl, mid, v), add(rs, mid + 1, r, mid + 1, xr, v); sum[n] = sum[ls] + sum[rs];}int query(int n, int l, int r, int xl, int xr){ if (l != r) down(n); if (xl <= l && r <= xr) return sum[n]; int mid = (l + r) >> 1; if (xr <= mid) return query(ls, l, mid, xl, xr); else if (xl > mid) return query(rs, mid + 1, r, xl, xr); else return query(ls, l, mid, xl, mid) + query(rs, mid + 1, r, mid + 1, xr);}int main(){ num = gi(); for (int i = 1; i <= num; ++i) a[i] = gi(); build(1, 1, num); m = gi(); for (int i = 1; i <= m; ++i){ scanf("%d", &bj); if (bj == 1) scanf("%d %d %d", &l, &r, &v), add(1, 1, num, l, r, v); else scanf("%d", &j), printf("%d\n", query(1, 1, num, j, j)); } return 0;}
Codevs 1082线段树练习3
#include <iostream>#include <cstdio>#include <cstdlib>#define ls (n << 1)#define rs (n << 1 | 1)#define L 1000000using namespace std;long long num, m, bj;long long a[L];long long size[L];long long lazy[L];long long sum[L];long long n, v, l, r, j, k;long long gi(){ char cj = getchar(); long long ans = 0; while (cj > '9' || cj < '0') cj = getchar(); while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar(); return ans;}void build(long long n, long long l, long long r){ size[n] = r - l + 1; if (l == r){ sum[n] = a[l]; return ; } long long mid = (l + r) >> 1; build(ls, l, mid), build(rs, mid + 1, r); sum[n] = sum[ls] + sum[rs];}void down(long long n){ sum[ls] += lazy[n] * size[ls]; sum[rs] += lazy[n] * size[rs]; lazy[ls] += lazy[n], lazy[rs] += lazy[n], lazy[n] = 0;}void add(long long n, long long l, long long r, long long xl, long long xr, long long v){ if (l != r) down(n); if (xl == l && r == xr){ sum[n] += v * size[n]; lazy[n] += v; return ; } long long mid = (l + r) >> 1; if (xr <= mid) add(ls, l, mid, xl, xr, v); else if (xl > mid) add(rs, mid + 1, r, xl, xr, v); else add(ls, l, mid, xl, mid, v), add(rs, mid + 1, r, mid + 1, xr, v); sum[n] = sum[ls] + sum[rs];}long long query(long long n, long long l, long long r, long long xl, long long xr){ if (l != r) down(n); if (xl <= l && r <= xr) return sum[n]; long long mid = (l + r) >> 1; if (xr <= mid) return query(ls, l, mid, xl, xr); else if (xl > mid) return query(rs, mid + 1, r, xl, xr); else return query(ls, l, mid, xl, mid) + query(rs, mid + 1, r, mid + 1, xr);}int main(){ num = gi(); for (int i = 1; i <= num; ++i) a[i] = gi(); build(1, 1, num); m = gi(); for (int i = 1; i <= m; ++i){ scanf("%lld", &bj); if (bj == 1) scanf("%lld %lld %lld", &l, &r, &v), add(1, 1, num, l, r, v); else scanf("%lld %lld", &j, &k), printf("%lld\n", query(1, 1, num, j, k)); } return 0;}
CJOJ P2162 - 线段树-magictree
线段树求和板子题
#include <iostream>#include <cstdio>#include <cstdlib>#define ls (n << 1)#define rs (n << 1 | 1)#define L 5000000using namespace std;long long num, m;long long a[L];long long size[L];long long lazy[L];long long sum[L];long long n, v, l, r, j, k;char bj;void build(long long n, long long l, long long r){ size[n] = r - l + 1; if (l == r){ sum[n] = a[l]; return ; } long long mid = (l + r) >> 1; build(ls, l, mid), build(rs, mid + 1, r); sum[n] = sum[ls] + sum[rs];}void down(long long n){ sum[ls] += lazy[n] * size[ls]; sum[rs] += lazy[n] * size[rs]; lazy[ls] += lazy[n], lazy[rs] += lazy[n], lazy[n] = 0;}void add(long long n, long long l, long long r, long long xl, long long xr, long long v){ if (l != r) down(n); if (xl == l && r == xr){ sum[n] += v * size[n]; lazy[n] += v; return ; } long long mid = (l + r) >> 1; if (xr <= mid) add(ls, l, mid, xl, xr, v); else if (xl > mid) add(rs, mid + 1, r, xl, xr, v); else add(ls, l, mid, xl, mid, v), add(rs, mid + 1, r, mid + 1, xr, v); sum[n] = sum[ls] + sum[rs];}long long query(long long n, long long l, long long r, long long xl, long long xr){ if (l != r) down(n); if (xl <= l && r <= xr) return sum[n]; long long mid = (l + r) >> 1; if (xr <= mid) return query(ls, l, mid, xl, xr); else if (xl > mid) return query(rs, mid + 1, r, xl, xr); else return query(ls, l, mid, xl, mid) + query(rs, mid + 1, r, mid + 1, xr);}int main(){ scanf("%d %d", &num, &m); for (int i = 0; i < num; ++i) scanf("%d", &a[i]); build(1, 0, num - 1); for (int i = 1; i <= m; ++i){ cin >> bj; if (bj == 'C') scanf("%lld %lld %lld", &l, &r, &v), add(1, 0, num - 1, l, r, v); if (bj == 'Q') scanf("%lld %lld", &j, &k), printf("%lld\n", query(1, 0, num - 1, j, k)); } return 0;}
CJOJ P2008 - 【JSOI2008】最大数
线段树求最大值的板子题
#include <iostream>#include <cstdio>#include <cstdlib>#define LL long long#define ls (n << 1)#define rs (n << 1 | 1)#define L 1000000using namespace std;LL t, l, x;LL m, d;char bj;LL num[L];void buildtree(int n, int l, int r) { if (l == r) { num[n] = 0; return ; } int mid = (l + r) >> 1; buildtree(ls, l, mid), buildtree(rs, mid + 1, r); num[n] = max(num[ls], num[rs]);}LL query(int n, int l, int r, int a, int b) { if (a == l && r == b) return num[n]; int mid = (l + r) >> 1; if (b <= mid) return query(ls, l, mid, a, b); else if (mid < a) return query(rs, mid + 1, r, a, b); else return max(query(ls, l, mid, a, mid), query(rs, mid + 1, r, mid + 1, b));}void add(int n, int l, int r, int a, LL v) { if (l == a && r == a) { num[n] = v; return ; } int mid = (l + r) >> 1; if (a <= mid) add(ls, l, mid, a, v); else add(rs, mid + 1, r, a, v); num[n] = max(num[ls], num[rs]);}int main() { scanf("%lld %lld", &m, &d); buildtree(1, 1, 210000); for (int i = 1; i <= m; ++i) { cin >> bj >> x; if (bj == 'Q') { t = query(1, 1, m, l - x + 1, l); printf("%lld", t); } if (bj == 'A') add(1, 1, m, ++l, (t + x) % d); } return 0;}
CJOJ P2265 线段覆盖
线段树区间修改板子题
#include <iostream>#include <cstdio>#include <cstdlib>#define L 1000000#define ls (n << 1)#define rs (n << 1 | 1)using namespace std;int l, n;int m, a, t;int x[L], cnt[L], len[L], rc[L], lc[L], lazy[L];void down(int n, int l, int r) { if (lazy[n] > 0) { cnt[n] = rc[n] = lc[n] = 1; len[n] = r - l + 1; } else { lc[n] = lc[ls]; rc[n] = rc[rs]; cnt[n] = cnt[ls] + cnt[rs]; if (rc[ls] == 1 && lc[rs] == 1) cnt[n]--; len[n] = len[ls] + len[rs]; }}void add(int n, int l, int r, int a, int b, int v) { if (a <= l && r <= b) { lazy[n] += v; if (l == r) { if (lazy[n] > 0) lazy[n] = rc[n] = lc[n] = cnt[n] = len[n] = 1; else lazy[n] = rc[n] = lc[n] = cnt[n] = len[n] = 0; } else down(n, l, r); } else { int mid = (l + r) >> 1; if (b > mid) add(rs, mid + 1, r, a, b, v); if (a <= mid) add(ls, l, mid, a, b, v); down(n, l, r); }}int main() { scanf("%d %d", &l, &n); for (int i = 1; i <= n; ++i) { scanf("%d %d %d", &m, &a, &t); if (m == 1) add(1, 1, l, a, a + t - 1, 1); else add(1, 1, l, a, a + t - 1, -1); printf("%d %d\n", cnt[1], len[1]); } return 0;}
总结未做的题
CJOJ P1810 - 【USACO 5.5.1】矩形周长
——CYCKN
0 0
- 线段树?线段树!
- 线段树?线段树!
- 线段_线段树
- 线段_线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- scrapy中解决pipeliine不能过滤中文的问题
- HTML5 canvas图形绘制基础(矩形,线条,渐变色,圆形,图片,多边形)
- jquery实现input点击输入框弹出日期
- ServletContext
- C#中virtual和abstract的区别
- 线段树
- Android之用AccessibilityService实现红包插件
- Toad学习总结
- C# SQL 整数变量
- 搭建自己的Blog (Github+Hexo)
- [006-Makefile-笔记] Makefile的条件判断
- 浅谈DOM解析
- Python魔法方法--基本的魔法方法
- 运动规划:Moveit输出规划轨迹到Gazebo