线段树_模版

摘要:
线段树线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。

线段树

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。

区间修改与求和

给出数的个数n以及操作数q:
对于q:
1 x y z 令区间[x, y]增加z
2 x y 求区间和

线段树_模版第1张线段树_模版第2张
1 #include<cstdio>
2 #include<cstring>
3 #include<iostream>
4 #define LL long long
5 using namespacestd;
6 const int maxn=1e5+10;
7 intn, q;
8 LL a[maxn];
9 LL sum[maxn<<2], li[maxn<<2];
10 
11 void _push_up(intrt) {
12     sum[rt]=sum[rt<<1]+sum[(rt<<1)|1];
13 }//向上更新,求区间和
14 
15 void _setup(int l, int r, intrt) {
16     li[rt]=0;
17     if(l==r){
18         sum[rt]=a[l];
19         return;
20 }
21     int mid=(l+r)>>1;
22     _setup(l, mid, rt<<1);
23     _setup(mid+1, r, (rt<<1)|1);
24 _push_up(rt);
25 }//建树
26 
27 void _push_down(int rt, intm) {
28     if(li[rt]) {
29         li[rt<<1]+=li[rt];
30         li[(rt<<1)|1]+=li[rt];
31         sum[rt<<1]+=li[rt]*(m-(m>>1));
32         sum[(rt<<1)|1]+=li[rt]*(m>>1);
33         li[rt]=0;
34 }
35 }//将li标记向下更新,传递给小区间
36 
37 void _add(int x, int y, LL z, int l ,int r, intrt) {
38     if(x<=l && y>=r) {
39         li[rt]+=z;
40         sum[rt]+=z*(r-l+1);
41         return;
42 }
43     _push_down(rt, r-l+1); //边算边更新,节省复杂度
44     int mid=(l+r)>>1;
45     if(x<=mid) _add(x, y, z, l, mid, rt<<1);
46     if(y>mid) _add(x, y, z, mid+1, r, (rt<<1)|1);
47 _push_up(rt);
48 }
49 
50 LL _query(int x, int y, int l, int r, intrt) {
51     if(x<=l && y>=r) {
52         returnsum[rt];
53 }
54     _push_down(rt, r-l+1); //求和时再顺便更新一次
55     int mid=(l+r)>>1;
56     LL ans=0;
57     if(x<=mid) ans+=_query(x, y, l, mid, rt<<1);
58     if(y>mid) ans+=_query(x, y, mid+1, r, (rt<<1)|1); //'夹'区间
59     returnans;
60 }
61 
62 intmain() {
63     scanf("%d%d", &n, &q);
64     for(int i=1; i<=n; i++) {
65         scanf("%lld", a+i);
66 }
67     _setup(1, n, 1);
68     for(int i=0; i<q; i++) {
69         intls;
70         scanf("%d", &ls);
71         if(ls==1) {
72             intx, y;
73 LL z;
74             scanf("%d%d%lld", &x, &y, &z);
75             _add(x, y, z, 1, n, 1);
76         } else if(ls==2) {
77             intx, y;
78             scanf("%d%d", &x, &y);
79             printf("%lld
", _query(x, y, 1, n ,1));
80 }
81 }
82     return 0;
83 }
View Code

区间最大值

描述:第1行给出数的个数n,操作数m
第2行为n个数
第3到m+3-1行有两个数a,b,求区间[a,b]中的最大数

样例:

Input

8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8

Output

9
9
7
7
9
8
7
9

代码:

线段树_模版第3张线段树_模版第4张
1 #include<cstdio>
2 #include<cstring>
3 #include<iostream>
4 #define CL(X,N) memset(X, N, sizeof(X))
5 #define LL long long
6 #define ls root<<1
7 #define rs root<<1|1
8 using namespacestd;
9 const int maxn=1e5+10;
10 intn, m;
11 int a[maxn], t[maxn<<2];
12 
13 void _pushup(introot) {
14     t[root]=max(t[ls], t[rs]);
15 }
16 
17 void _set(int l, int r, introot) {
18     if(l==r) {
19         t[root]=a[l];
20         return;
21 }
22     int mid=(l+r)>>1;
23 _set(l, mid, ls);
24     _set(mid+1, r, rs);
25 _pushup(root);
26 }
27 
28 int _query(int l, int r, int root, int a, intb) {
29     if(a<=l && b>=r) {
30         returnt[root];
31 }
32     int mid=(l+r)>>1, ans=0;
33     if(a<=mid) ans=_query(l, mid, ls, a, b);
34     if(b>mid) ans=max(ans, _query(mid+1, r, rs, a, b));
35     returnans;
36 }
37 
38 intmain() {
39     scanf("%d%d", &n, &m);
40     for(int i=1; i<=n; i++) {
41         scanf("%d", a+i);
42 }
43     _set(1, n, 1);
44     for(int i=0; i<m; i++) {
45         inta, b;
46         scanf("%d%d", &a, &b);
47         printf("%d
", _query(1, n, 1, a, b));
48 }
49     return 0;
50 }
View Code

指针版:

线段树_模版第5张线段树_模版第6张
1 #include<cstdio>
2 #include<cstring>
3 #include<iostream>
4 #define CL(X,N) memset(X, N, sizeof(X))
5 #define LL long long
6 using namespacestd;
7 const int maxn=1e5+10;
8 intn, m;
9 inta[maxn];
10 structBit {
11     intl, r, data;
12     Bit *ls, *rs;
13 Bit(){
14         l=0, r=0, data=0;
15         ls=rs=NULL;
16 }
17 }*t;
18 
19 #define lc root->ls
20 #define rc root->rs
21 void _pushup(Bit *root) {
22     root->data=max(lc->data, rc->data);
23 }
24 
25 void _set(int l, int r, Bit *root) {
26     root->l=l;
27     root->r=r;
28     if(l==r) {
29         root->data=a[l];
30         return;
31 }
32     if(!lc) lc=newBit;
33     if(!rc) rc=newBit;
34     int mid=(l+r)>>1;
35 _set(l, mid, lc);
36     _set(mid+1, r, rc);
37 _pushup(root);
38 }
39 
40 int _query(Bit *root, int a, intb) {
41     if(!root) return 0;
42     int l=root->l, r=root->r;
43     if(a<=l && b>=r) {
44         return root->data;
45 }
46     int mid=(l+r)>>1, ans=0;
47     if(a<=mid) ans=_query(lc, a, b);
48     if(b>mid) ans=max(ans, _query(rc, a, b));
49     returnans;
50 }
51 
52 intmain() {
53     t=newBit;
54     scanf("%d%d", &n, &m);
55     for(int i=1; i<=n; i++) {
56         scanf("%d", a+i);
57 }
58     _set(1, n, t);
59     for(int i=0; i<m; i++) {
60         intx, y;
61         scanf("%d%d", &x, &y);
62         printf("%d
", _query(t, x, y));
63 }
64     return 0;
65 }
View Code

为什么写指针?

因为不容易MLE(不存在访问无效内存),但是写起来会需要小心一点

免责声明:文章转载自《线段树_模版》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MQTT协议学习及实践(Linux服务端,Android客户端的例子)虚拟机调试ionic项目下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

4.18 省选模拟赛 消息传递 树剖 倍增 线段树维护等比数列

把树剖和倍增 线段树的联系诠释的很完美。 题目意思:自行理解。 做法:设两个点x,y x能挡住y 且在k点处 那么至少的得到一个式子 tx+dx-dk<tx+dy-dk 从这个式子中可以发现 按tx+dx这个排序 前面的可以有可能挡住后面的 同时相等时题目中的要求小的编号优先。 我们考虑一个点挡住当前的这个点的去路 设sx表示x这个点当前不能通过的...

链表的建立

#include <stdio.h> #include <stdlib.h> #define null 0 typedef struct snode { char *name; char *no; int score[5]; }typedefdata; typedef struct node { typedefdata data;...

[POJ1195] Mobile phones(二维树状数组)

题目链接:http://poj.org/problem?id=1195 题意:四种操作: 0:初始化一个S*S的零矩阵 1:点(x,y)是值+A 2:查询一个子矩阵里所有数的和 3:退出 线段树由于不能在两棵树之间传递标记,所以这种求和的操作非常难处理。 改学了一下而为树状数组,发现可是比二维线段树简单多了。 记得之前曾经看过zkw线段树的ppt讲稿,好像...

getchar()和scanf()混合使用的坑

最近在混合使用 getchar() 和 scanf() 的时候遇到一个坑,现在记录一下。 代码中使用 getchar() 处理字符输入,用 scanf() 处理数字输入。 getchar() 读取每个字符,包括空格、制表符和换行符; 而 scanf() 在读取数字时则会跳过空格、 制表符和换行符。 比如下面这个程序,读入一个字符和两个数字,然后根据输入的两...

2019CCPC秦皇岛

D - Decimal 代码: #include <bits/stdc++.h> using namespace std; const int maxn=1e6; int main() { int n,t; scanf("%d",&t); while(t--) { scanf("%d",&...

Atlantis(POJ1151+线段树+扫描线)

题目链接:http://poj.org/problem?id=1151 题目: 题意:求所有矩形的面积,重合部分只算一次。 思路:扫描线入门题,推荐几篇学扫描线的博客: 1.http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html 2.https://blog.csdn.ne...