首页 > 代码库 > 线段树基础

线段树基础

关于线段树的原理学习,可以参看杨弋大牛的论文《线段树》以及刘汝佳老师的《算法竞赛入门经典(训练指南)》,代码风格学习hzwer或者notonlysuccess均可。

一.单点更新

最基础的线段树

题目:codevs1080

链接:http://codevs.cn/problem/1080/

分析:最简单的线段树,单点更新,区间求和

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn=100000+10;
 5 struct data{
 6     int left,right; //左右端点
 7     int sum; //结点的和
 8 }Tree[maxn<<2];
 9 int n,m;
10 int a[maxn];
11 //建树过程
12 void build(int l,int r,int rt){
13     Tree[rt].left=l;Tree[rt].right=r;
14     if(l==r){  //叶结点直接插入值
15         Tree[rt].sum=a[l];
16         return;
17     }
18     int mid=(l+r)>>1;
19     build(l,mid,rt<<1);
20     build(mid+1,r,rt<<1|1);
21     Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
22 }
23 
24 //单点更新
25 void update(int x,int y,int rt){
26     Tree[rt].sum+=y;
27     int l=Tree[rt].left,r=Tree[rt].right;
28     if(l==r) return;
29     int mid=(l+r)>>1;
30     if(x<=mid)  update(x,y,rt<<1);
31     else update(x,y,rt<<1|1);
32 }
33 
34 //区间求和
35 int query(int l,int r,int rt){
36     int L=Tree[rt].left,R=Tree[rt].right;
37     if(L==l&&r==R){
38         return Tree[rt].sum;
39     }
40     int mid=(L+R)/2;
41     if(r<=mid) return query(l,r,rt<<1);
42     if(l>mid) return query(l,r,rt<<1|1);
43     return query(l,mid,rt<<1)+query(mid+1,r,rt<<1|1);
44 }
45 int main()
46 {
47     scanf("%d",&n);
48     for(int i=1;i<=n;i++){
49         scanf("%d",&a[i]);
50     }
51     build(1,n,1);
52     scanf("%d",&m);
53     while(m--){
54         int num,x,y;
55         scanf("%d%d%d",&num,&x,&y);
56         if(num==1) update(x,y,1);
57         else printf("%d\n",query(x,y,1));
58     }
59     return 0;
60 }
View Code

 

二.区间更新

从单点更新一直到区间更新是初学者的一道坎,主要我们要深刻理解lazy操作,因为区间更新有时候并不需要像单点那样更新到子节点

推荐一篇博客:http://blog.csdn.net/dreamzuora/article/details/52781831

题目:codevs1082

链接:http://codevs.cn/problem/1082/

分析:区间更新,区间求和

技术分享
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 using namespace std;
 5 const int maxn=200000+10;
 6 struct data{
 7     int left,right;
 8     long long sum; //区间和
 9     int val;  //标记延迟
10 }Tree[maxn<<2];
11 int a[maxn];
12 int n,m;
13 
14 //建树
15 void build(int l,int r,int rt){
16     Tree[rt].left=l;Tree[rt].right=r;
17     if(l==r){
18         Tree[rt].sum=a[l];
19         return;
20     }
21     int mid=(l+r)>>1;
22     Tree[rt].val=0;
23     build(l,mid,rt<<1);
24     build(mid+1,r,rt<<1|1);
25     Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
26 }
27 
28 //更新子节点
29 void pushdown(int rt){
30     int x=Tree[rt].right-Tree[rt].left+1;
31     Tree[rt<<1].val+=Tree[rt].val;
32     Tree[rt<<1|1].val+=Tree[rt].val;
33     Tree[rt<<1].sum+=(x-(x>>1))*Tree[rt].val;
34     Tree[rt<<1|1].sum+=(x>>1)*Tree[rt].val;
35     Tree[rt].val=0;
36 }
37 
38 //区间更新
39 void update(int l,int r,int x,int rt){
40     int L=Tree[rt].left,R=Tree[rt].right;
41     if(L==l&&R==r){
42         Tree[rt].val+=x;
43         Tree[rt].sum+=(R-L+1)*x;
44         return;
45     }
46     int mid=(L+R)>>1;
47     if(Tree[rt].val) pushdown(rt);
48     if(r<=mid) update(l,r,x,rt<<1);
49     else if(l>mid)  update(l,r,x,rt<<1|1);
50     else{
51         update(l,mid,x,rt<<1);
52         update(mid+1,r,x,rt<<1|1);
53     }
54     Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
55 }
56 
57 //区间查询
58 long long query(int l,int r,int rt){
59     int L=Tree[rt].left,R=Tree[rt].right;
60     if(L==l&&R==r){
61         return Tree[rt].sum;
62     }
63     if(Tree[rt].val) pushdown(rt);
64     int mid=(L+R)>>1;
65     if(r<=mid) return query(l,r,rt<<1);
66     if(l>mid) return query(l,r,rt<<1|1);
67     return query(l,mid,rt<<1)+query(mid+1,r,rt<<1|1);
68 }
69 int main()
70 {
71     scanf("%d",&n);
72     for(int i=1;i<=n;i++)
73         scanf("%d",&a[i]);
74     build(1,n,1);
75     scanf("%d",&m);
76     while(m--){
77         int num;
78         int x,y,d;
79         scanf("%d",&num);
80         if(num==1){
81             scanf("%d%d%d",&x,&y,&d);
82             update(x,y,d,1);
83         }else{
84             scanf("%d%d",&x,&y);
85             printf("%lld\n",query(x,y,1));
86         }
87     }
88 }
View Code

 

线段树基础