线段树模板

线段树是一种常用的算法,本人近日试着学习了一下,发现好难啊。。

下面是我学习了几天打的模板

 1 int a[100001],sum[100001]; //sum表示线段树,空间O(2n),a表示序列 
 2 
 3 //建立一颗线段树 
 4 void change(int root){
 5     sum[root]=sum[root*2]+sum[root*2+1];
 6 }
 7 void buildtree(int root,int l,int r){
 8     if (l==r) {
 9         sum[root]=a[l]; return;
10     }
11     int mid= l+r>>1;
12     buildtree(root*2,l,mid);
13     buildtree(root*2+1,mid+1,r);
14     change(root);
15 }   
16 
17 //单点修改q
18 void change(int root){
19     sum[root]=sum[root*2]+sum[root*2+1];
20 }
21 void change (int root,int l,int r,int p,int q){
22     if (l==r) {
23         sum[root]+=q; 
24         return;
25     }
26     int mid=l+r>>1;
27     if (p<=mid) change(root*2,l,mid,p,q);
28     else change(root*2+1,mid+1,r,p,q);
29     change(root);
30 } 
31 
32 //求区间和[L,R]
33 int find(int root,int l,int r,int L,int R){
34     if (r<L||l>R) return 0;
35     if (l>=L&&r<=R) return sum[root];
36     int mid=l+r>>1;
37     return find(root*2,l,mid)+find(root*2+1,mid+1,r);
38 } 
39 
40 //求最大子段和问题
41 int L[100001],R[100001],ans[100001]; //L表示前缀和,R表示后缀和,ans表示答案 
42 void change(int root){
43     sum[root]=sum[root*2]+sum[root*2+1];
44     
45     L[root]=max(L[root*2],sum[root*2]+L[root*2+1]);
46     R[root]=max(R[root*2+1],sum[root*2+1]+R[root*2]);
47     
48     ans[root]=max(max(ans[root*2],ans[root*2+1]),R[root*2]+L[root*2+1]);
49 }//ans即为解 find中把sum改为ans即可 
50  
51 //区间修改,区间加,打懒标记
52 //区间加 区间和 
53 [L,R] +x
54 int A[410000],sum[410000];
55 void pushdown(int k1){ //把懒标记带下去 
56     A[k1*2]+=A[k1]; A[k1*2+1]+=A[k1]; A[k1]=0;
57 }
58 void addall(int k1,int l,int r,int L,int R){
59     if (l>R||r<L) return;
60     if (L<=l&&R>=r){
61         sum[k1]+=x*(r-l+1); //快速更新 
62         A[k1]+=x; return;
63     }
64     int mid=l+r>>1; pushdown(k1);
65     addall(k1*2,l,mid,L,R);
66     addall(k1*2+1,mid+1,r,L,R);
67     change(k1);
68 }
69 int find(int k1,int l,int r,int L,int R){
70     if (l>R||r<L) return 0;
71     if (L<=l&&R>=r) return sum[k1];
72     int mid=l+r>>1; pushdown(k1);
73     return find(k1*2,l,mid,L,R)+find(k1*2+1,mid+1,r,L,R);
74 }
75 
76 //有懒标记的线段树
77 
78 //1.change()
79 //2.pushdown() -> 两个标记的合并 +5 +6 => +11
80 //3.再给一个节点打上懒标记的时候需要快速更新维护的信息 

 

int a[100001],sum[100001]; //sum表示线段树,空间O(2n),a表示序列 
//建立一颗线段树 void change(int root){sum[root]=sum[root*2]+sum[root*2+1];}void buildtree(int root,int l,int r){if (l==r) {sum[root]=a[l]; return;}int mid= l+r>>1;buildtree(root*2,l,mid);buildtree(root*2+1,mid+1,r);change(root);}   
//单点修改qvoid change(int root){sum[root]=sum[root*2]+sum[root*2+1];}void change (int root,int l,int r,int p,int q){if (l==r) {sum[root]+=q; return;}int mid=l+r>>1;if (p<=mid) change(root*2,l,mid,p,q);else change(root*2+1,mid+1,r,p,q);change(root);} 
//求区间和[L,R]int find(int root,int l,int r,int L,int R){if (r<L||l>R) return 0;if (l>=L&&r<=R) return sum[root];int mid=l+r>>1;return find(root*2,l,mid)+find(root*2+1,mid+1,r);} 
//求最大子段和问题int L[100001],R[100001],ans[100001]; //L表示前缀和,R表示后缀和,ans表示答案 void change(int root){sum[root]=sum[root*2]+sum[root*2+1];L[root]=max(L[root*2],sum[root*2]+L[root*2+1]);R[root]=max(R[root*2+1],sum[root*2+1]+R[root*2]);ans[root]=max(max(ans[root*2],ans[root*2+1]),R[root*2]+L[root*2+1]);}//ans即为解 find中把sum改为ans即可  //区间修改,区间加,打懒标记//区间加 区间和 [L,R] +xint A[410000],sum[410000];void pushdown(int k1){ //把懒标记带下去 A[k1*2]+=A[k1]; A[k1*2+1]+=A[k1]; A[k1]=0;}void addall(int k1,int l,int r,int L,int R){if (l>R||r<L) return;if (L<=l&&R>=r){sum[k1]+=x*(r-l+1); //快速更新 A[k1]+=x; return;}int mid=l+r>>1; pushdown(k1);addall(k1*2,l,mid,L,R);addall(k1*2+1,mid+1,r,L,R);change(k1);}int find(int k1,int l,int r,int L,int R){if (l>R||r<L) return 0;if (L<=l&&R>=r) return sum[k1];int mid=l+r>>1; pushdown(k1);return find(k1*2,l,mid,L,R)+find(k1*2+1,mid+1,r,L,R);}
//有懒标记的线段树
//1.change()//2.pushdown() -> 两个标记的合并 +5 +6 => +11//3.再给一个节点打上懒标记的时候需要快速更新维护的信息 

 

posted @ 2017-01-25 13:17  lztlztlzt  阅读(140)  评论(0编辑  收藏  举报