线段树
线段树的作用:
1.多次查询区间的最大值,最小值,以及区间和
2.多次更新区间的元素值(可以元素值替换,也可加上一个给定输入值)
#include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <queue> #define MAXN 100010 #define inf 0x3f3f3f3f #include<iostream> using namespace std; struct node{ int l,r;//区间[l,r] int add;//区间的延时标记 int sum;//区间和 int mx; //区间最大值 int mn; //区间最小值 }tree[MAXN<<2];//一定要开到4倍多的空间 void pushup(int index){ tree[index].sum = tree[index<<1].sum+tree[index<<1|1].sum; tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx); tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn); } void pushdown(int index){ //说明该区间之前更新过 //要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新 if(tree[index].add){ //替换原来的值 /* tree[index<<1].sum = (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; tree[index<<1|1].sum = (tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; tree[index<<1].mx = tree[index].add; tree[index<<1|1].mx = tree[index].add; tree[index<<1].mn = tree[index].add; tree[index<<1|1].mn = tree[index].add; tree[index<<1].add = tree[index].add; tree[index<<1|1].add = tree[index].add; tree[index].add = 0;*/ //在原来的值的基础上加上val tree[index<<1].sum += (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; tree[index<<1|1].sum +=(tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; tree[index<<1].mx += tree[index].add; tree[index<<1|1].mx += tree[index].add; tree[index<<1].mn += tree[index].add; tree[index<<1|1].mn += tree[index].add; tree[index<<1].add += tree[index].add; tree[index<<1|1].add += tree[index].add; tree[index].add = 0; } } void build(int l,int r,int index){ tree[index].l = l; tree[index].r = r; tree[index].add = 0;//刚开始一定要清0 if(l == r){ scanf("%d",&tree[index].sum); tree[index].mn = tree[index].mx = tree[index].sum; return ; } int mid = (l+r)>>1; build(l,mid,index<<1); build(mid+1,r,index<<1|1); pushup(index); } void updata(int l,int r,int index,int val){ if(l <= tree[index].l && r >= tree[index].r){ /*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1 个数,所以区间和 以及 最值为: */ /*
tree[index].sum = (tree[index].r-tree[index].l+1)*val; tree[index].mn = val; tree[index].mx = val; tree[index].add = val;//延时标记
*/ //在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1 //个数,所以区间和 以及 最值为: tree[index].sum += (tree[index].r-tree[index].l+1)*val; tree[index].mn += val; tree[index].mx += val; tree[index].add += val;//延时标记 return ; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; if(l <= mid){ updata(l,r,index<<1,val); } if(r > mid){ updata(l,r,index<<1|1,val); } pushup(index); } int query(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; return tree[index].mx; //return tree[index].mn; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int ans = 0; int Max = 0; int Min = inf; if(l <= mid){ ans += query(l,r,index<<1); Max = max(query(l,r,index<<1),Max); Min = min(query(l,r,index<<1),Min); } if(r > mid){ ans += query(l,r,index<<1|1); Max = max(query(l,r,index<<1|1),Max); Min = min(query(l,r,index<<1|1),Min); } //return ans; return Max; //return Min; } int query1(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; // return tree[index].mx; return tree[index].mn; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int Min = inf; if(l <= mid){ Min = min(query(l,r,index<<1),Min); } if(r > mid){ Min = min(query(l,r,index<<1|1),Min); } return Min; } int query2(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ return tree[index].sum; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int ans = 0; if(l <= mid){ ans += query(l,r,index<<1); } if(r > mid){ ans += query(l,r,index<<1|1); } return ans; } int main() { int n,m,q,x,y,z; while(~scanf("%d%d",&n,&m)){ build(1,n,1); while(m--){ scanf("%d",&q); if(q == 1){ cout<<"查询:(x,y)的最大值"<<endl; scanf("%d %d",&x,&y); cout<<query(x,y,1)<<endl; } else if(q==2){ cout<<"查询:(x,y)的最小值"<<endl; scanf("%d %d",&x,&y); cout<<query1(x,y,1)<<endl; } else if(q==3){ cout<<"查询:(x,y)的和"<<endl; scanf("%d %d",&x,&y); cout<<query2(x,y,1)<<endl; } else{ cout<<"更新(x,y),区间每个数加上z:"<<endl; scanf("%d %d %d",&x,&y,&z); updata(x,y,1,z); for(int i = 1; i <= n; ++i){ printf("a[%d] = %d\n",i,query(i,i,1)); } } } } return 0; } /* 8 10 8 1 9 10 2 4 5 0 */
2.主席树
作用:
相关博客:
http://www.imooc.com/article/73393

1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 long long n,m,ans,x,y,ch,val; 5 struct ahah 6 { 7 long long l,r,sum,f; 8 } tree[200000<<2]; 9 void build(int k,int l,int r) 10 { 11 tree[k].l=l; 12 tree[k].r=r; 13 if(tree[k].l==tree[k].r) 14 { 15 scanf("%lld",&tree[k].sum);//输入端点的值 16 //tree[k].sum=0; 17 // cout<<"?"<<endl; 18 return ; 19 } 20 long long mid=(tree[k].l+tree[k].r)>>1; 21 build(k<<1,l,mid); 22 build(k<<1|1,mid+1,r); 23 tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; 24 } 25 void update(int k) 26 { 27 if(tree[k].l==tree[k].r) 28 { 29 tree[k].sum+=y; 30 return ; 31 } 32 long long mid=(tree[k].l+tree[k].r)>>1; 33 if(x<=mid) 34 update(k<<1); 35 else 36 update(k<<1|1); 37 tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; 38 } 39 void down(long long k) 40 { 41 tree[k<<1].f+=tree[k].f; 42 tree[k<<1|1].f+=tree[k].f; 43 tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].f; 44 tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].f; 45 tree[k].f=0; 46 } 47 void query(int k) 48 { 49 if(x<=tree[k].l&&y>=tree[k].r) 50 { 51 ans+=tree[k].sum; 52 return ; 53 } 54 if(tree[k].f) 55 down(k); 56 long long mid=(tree[k].l+tree[k].r)>>1; 57 if(x<=mid) 58 query(k<<1); 59 if(y>mid) 60 query(k<<1|1); 61 } 62 void add(long long k) 63 { 64 if(tree[k].l>=x&&tree[k].r<=y) 65 { 66 tree[k].sum+=(tree[k].r-tree[k].l+1)*val; 67 tree[k].f+=val; 68 return ; 69 } 70 if(tree[k].f) 71 down(k); 72 long long mid=(tree[k].l+tree[k].r)>>1; 73 if(x<=mid) 74 add(k<<1); 75 if(y>mid) 76 add(k<<1|1); 77 tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; 78 } 79 int main() 80 { 81 scanf("%lld%lld",&n,&m);//n个数,m个操作 82 build(1,1,n);//输入n个端点的值 83 for(int i=1; i<=m; i++) 84 { 85 ans=0; 86 cin>>ch>>x>>y;//操作类型,区间左下标,区间右下标 87 if(ch==1)//区间修改 88 { 89 cin>>val; 90 add(1); 91 } 92 else//区间查询 93 { 94 query(1); 95 cout<<ans<<"\n"; 96 } 97 } 98 }
输入:
8 4
4 2 5 7 9 1 0 3
2 1 3
1 1 3
2 1 3
2 1 1
输出:
11
20
7
https://blog.csdn.net/qq_36553623/article/details/82988354

1 #include <string.h> 2 #include <algorithm> 3 #include <stdio.h> 4 #include <math.h> 5 #include <queue> 6 #define MAXN 100010 7 #define inf 0x3f3f3f3f 8 #include<iostream> 9 using namespace std; 10 11 struct node{ 12 int l,r;//区间[l,r] 13 int add;//区间的延时标记 14 int sum;//区间和 15 int mx; //区间最大值 16 int mn; //区间最小值 17 }tree[MAXN<<2];//一定要开到4倍多的空间 18 19 void pushup(int index){ 20 tree[index].sum = tree[index<<1].sum+tree[index<<1|1].sum; 21 tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx); 22 tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn); 23 } 24 void pushdown(int index){ 25 //说明该区间之前更新过 26 //要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新 27 if(tree[index].add){ 28 //替换原来的值 29 /* 30 tree[index<<1].sum = (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; 31 tree[index<<1|1].sum = (tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; 32 tree[index<<1].mx = tree[index].add; 33 tree[index<<1|1].mx = tree[index].add; 34 tree[index<<1].mn = tree[index].add; 35 tree[index<<1|1].mn = tree[index].add; 36 tree[index<<1].add = tree[index].add; 37 tree[index<<1|1].add = tree[index].add; 38 tree[index].add = 0;*/ 39 //在原来的值的基础上加上val 40 41 tree[index<<1].sum += (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; 42 tree[index<<1|1].sum +=(tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; 43 tree[index<<1].mx += tree[index].add; 44 tree[index<<1|1].mx += tree[index].add; 45 tree[index<<1].mn += tree[index].add; 46 tree[index<<1|1].mn += tree[index].add; 47 tree[index<<1].add += tree[index].add; 48 tree[index<<1|1].add += tree[index].add; 49 tree[index].add = 0; 50 51 } 52 } 53 void build(int l,int r,int index){ 54 tree[index].l = l; 55 tree[index].r = r; 56 tree[index].add = 0;//刚开始一定要清0 57 if(l == r){ 58 scanf("%d",&tree[index].sum); 59 tree[index].mn = tree[index].mx = tree[index].sum; 60 return ; 61 } 62 int mid = (l+r)>>1; 63 build(l,mid,index<<1); 64 build(mid+1,r,index<<1|1); 65 pushup(index); 66 } 67 void updata(int l,int r,int index,int val){ 68 if(l <= tree[index].l && r >= tree[index].r){ 69 /*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1 70 个数,所以区间和 以及 最值为: 71 */ 72 /*tree[index].sum = (tree[index].r-tree[index].l+1)*val; 73 tree[index].mn = val; 74 tree[index].mx = val; 75 tree[index].add = val;//延时标记*/ 76 //在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1 77 //个数,所以区间和 以及 最值为: 78 tree[index].sum += (tree[index].r-tree[index].l+1)*val; 79 tree[index].mn += val; 80 tree[index].mx += val; 81 tree[index].add += val;//延时标记 82 83 return ; 84 } 85 pushdown(index); 86 int mid = (tree[index].l+tree[index].r)>>1; 87 if(l <= mid){ 88 updata(l,r,index<<1,val); 89 } 90 if(r > mid){ 91 updata(l,r,index<<1|1,val); 92 } 93 pushup(index); 94 } 95 int query(int l,int r,int index){ 96 if(l <= tree[index].l && r >= tree[index].r){ 97 //return tree[index].sum; 98 return tree[index].mx; 99 //return tree[index].mn; 100 } 101 pushdown(index); 102 int mid = (tree[index].l+tree[index].r)>>1; 103 int ans = 0; 104 int Max = 0; 105 int Min = inf; 106 if(l <= mid){ 107 ans += query(l,r,index<<1); 108 Max = max(query(l,r,index<<1),Max); 109 Min = min(query(l,r,index<<1),Min); 110 } 111 if(r > mid){ 112 ans += query(l,r,index<<1|1); 113 Max = max(query(l,r,index<<1|1),Max); 114 Min = min(query(l,r,index<<1|1),Min); 115 } 116 //return ans; 117 return Max; 118 //return Min; 119 } 120 int main() 121 { 122 int n,m,q,x,y,z; 123 while(~scanf("%d%d",&n,&m)){ 124 build(1,n,1); 125 while(m--){ 126 scanf("%d",&q); 127 if(q == 1){ 128 cout<<"查询:(x,y)"<<endl; 129 scanf("%d %d",&x,&y); 130 cout<<query(x,y,1)<<endl; 131 } 132 else{ 133 cout<<"更新(x,y)为z:"<<endl; 134 scanf("%d %d %d",&x,&y,&z); 135 updata(x,y,1,z); 136 for(int i = 1; i <= n; ++i){ 137 printf("a[%d] = %d\n",i,query(i,i,1)); 138 } 139 } 140 } 141 } 142 return 0; 143 }
#include <string.h>#include <algorithm>#include <stdio.h>#include <math.h>#include <queue>#define MAXN 100010#define inf 0x3f3f3f3f#include<iostream>using namespace std;struct node{ int l,r;//区间[l,r] int add;//区间的延时标记 int sum;//区间和 int mx; //区间最大值 int mn; //区间最小值}tree[MAXN<<2];//一定要开到4倍多的空间
void pushup(int index){ tree[index].sum = tree[index<<1].sum+tree[index<<1|1].sum; tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx); tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn);}void pushdown(int index){ //说明该区间之前更新过 //要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新 if(tree[index].add){ //替换原来的值 /* tree[index<<1].sum = (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; tree[index<<1|1].sum = (tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; tree[index<<1].mx = tree[index].add; tree[index<<1|1].mx = tree[index].add; tree[index<<1].mn = tree[index].add; tree[index<<1|1].mn = tree[index].add; tree[index<<1].add = tree[index].add; tree[index<<1|1].add = tree[index].add; tree[index].add = 0;*/ //在原来的值的基础上加上val tree[index<<1].sum += (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; tree[index<<1|1].sum +=(tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; tree[index<<1].mx += tree[index].add; tree[index<<1|1].mx += tree[index].add; tree[index<<1].mn += tree[index].add; tree[index<<1|1].mn += tree[index].add; tree[index<<1].add += tree[index].add; tree[index<<1|1].add += tree[index].add; tree[index].add = 0;
}}void build(int l,int r,int index){ tree[index].l = l; tree[index].r = r; tree[index].add = 0;//刚开始一定要清0 if(l == r){ scanf("%d",&tree[index].sum); tree[index].mn = tree[index].mx = tree[index].sum; return ; } int mid = (l+r)>>1; build(l,mid,index<<1); build(mid+1,r,index<<1|1); pushup(index);}void updata(int l,int r,int index,int val){ if(l <= tree[index].l && r >= tree[index].r){ /*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1 个数,所以区间和 以及 最值为: */ /*tree[index].sum = (tree[index].r-tree[index].l+1)*val; tree[index].mn = val; tree[index].mx = val; tree[index].add = val;//延时标记*/ //在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1 //个数,所以区间和 以及 最值为: tree[index].sum += (tree[index].r-tree[index].l+1)*val; tree[index].mn += val; tree[index].mx += val; tree[index].add += val;//延时标记 return ; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; if(l <= mid){ updata(l,r,index<<1,val); } if(r > mid){ updata(l,r,index<<1|1,val); } pushup(index);}int query(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; return tree[index].mx; //return tree[index].mn; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int ans = 0; int Max = 0; int Min = inf; if(l <= mid){ ans += query(l,r,index<<1); Max = max(query(l,r,index<<1),Max); Min = min(query(l,r,index<<1),Min); } if(r > mid){ ans += query(l,r,index<<1|1); Max = max(query(l,r,index<<1|1),Max); Min = min(query(l,r,index<<1|1),Min); } //return ans; return Max; //return Min;}int query1(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; // return tree[index].mx; return tree[index].mn; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int Min = inf; if(l <= mid){ Min = min(query(l,r,index<<1),Min); } if(r > mid){ Min = min(query(l,r,index<<1|1),Min); } return Min;}
int query2(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ return tree[index].sum; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int ans = 0; if(l <= mid){ ans += query(l,r,index<<1); } if(r > mid){ ans += query(l,r,index<<1|1); } return ans;}
int main(){ int n,m,q,x,y,z; while(~scanf("%d%d",&n,&m)){ build(1,n,1); while(m--){ scanf("%d",&q); if(q == 1){ cout<<"查询:(x,y)的最大值"<<endl; scanf("%d %d",&x,&y); cout<<query(x,y,1)<<endl; } else if(q==2){ cout<<"查询:(x,y)的最小值"<<endl; scanf("%d %d",&x,&y); cout<<query1(x,y,1)<<endl; } else if(q==3){ cout<<"查询:(x,y)的和"<<endl; scanf("%d %d",&x,&y); cout<<query2(x,y,1)<<endl; } else{ cout<<"更新(x,y),区间每个数加上z:"<<endl; scanf("%d %d %d",&x,&y,&z); updata(x,y,1,z); for(int i = 1; i <= n; ++i){ printf("a[%d] = %d\n",i,query(i,i,1)); } } } } return 0;}/*8 108 1 9 10 2 4 5 0*/
zkw线段树