標籤:style os io for ar html amp log
線段樹研究了兩天了,總算有了點眉目,今天也把落下的題,補了一下。 貼一份線段樹模板
線段樹的特點:
1. 每一層都是區間[a, b]的一個劃分,記 L = b - a
2. 一共有log2L層
3. 給定一個點p,從根到葉子p上的所有區間都包含點p,且其他區間都不包含點p。
4. 給定一個區間[l; r],可以把它分解為不超過2log2 L條不相交線段的並。
總結來說:線段樹最近本的應用是4點:
1.單點更新:單點替換、單點增減
2.單點詢問
3.區間詢問:區間之和、區間最值
4.區間更新:區間替換、區間增減
下面是 這4個基本操作的模板:(有點兒挫)
單點替換 區間求最大
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>using namespace std;#define N 200004#define MAX INT_MAX#define MIN INT_MINstruct node{int left,right;int num; //}T[4*N];int ans=0;void Creat(int left,int right,int id)//建樹{T[id].left =left;T[id].right =right;T[id].num =0;if(T[id].left ==T[id].right )return ;Creat(left,(left+right)/2,2*id);Creat((left+right)/2+1,right,2*id+1);}void UPdata(int id,int i,int j){if(T[id].left<=i&&T[id].right >=i)T[id].num = j;if(T[id].left ==T[id].right )return;if(i>T[id].right )return;if(i<T[id].left )return;int mid=(T[id].left +T[id].right )/2;if(i<=mid)UPdata(id*2,i,j);elseUPdata(id*2+1,i,j);T[id].num = max(T[id*2].num,T[id*2+1].num);}void query(int id,int l,int r)//區間&&單點查詢,l-r 區間內的所有人{int mid=(T[id].left +T[id].right)/2;if(T[id].left ==l&&T[id].right ==r){if(T[id].num >ans) ans = T[id].num;return;}if(r<=mid)query(2*id,l,r);else if(l>mid)query(2*id+1,l,r);else{query(2*id,l,mid);query(2*id+1,mid+1,r);}}int main(){ int n,m,x,l,r; char str[5]; while(scanf("%d%d",&n,&m)!=EOF) { Creat(1,n,1); for(int i = 1;i<=n;i++) { scanf("%d",&x); UPdata(1,i,x); } for(int i = 1;i<=m;i++) { scanf("%s",str); if(str[0]=='Q') { scanf("%d%d",&l,&r); ans = -9999999; query(1,l,r); printf("%d\n",ans); ans = -9999999; } else if(str[0]=='U') { scanf("%d%d",&l,&r); UPdata(1,l,r); } } } return 0;}
單點增減 區間求和
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>using namespace std;#define N 50004#define MAX INT_MAX#define MIN INT_MINstruct node{int left,right;int num; //}T[4*N];int ans=0;void Creat(int left,int right,int id)//建樹{T[id].left =left;T[id].right =right;T[id].num =0;if(T[id].left ==T[id].right )return ;Creat(left,(left+right)/2,2*id);Creat((left+right)/2+1,right,2*id+1);}void UPdata(int id,int i,int j)//單點更新{if(T[id].left<=i&&T[id].right >=i)T[id].num +=j;if(T[id].left ==T[id].right )return;if(i>T[id].right )return;if(i<T[id].left )return;int mid=(T[id].left +T[id].right )/2;if(i<=mid)UPdata(id*2,i,j);elseUPdata(id*2+1,i,j);}void query(int id,int l,int r)//區間&&單點查詢{int mid=(T[id].left +T[id].right)/2;if(T[id].left ==l&&T[id].right ==r){ans+=T[id].num ;return;}if(r<=mid)query(2*id,l,r);else if(l>mid)query(2*id+1,l,r);else{query(2*id,l,mid);query(2*id+1,mid+1,r);}}int main(){int t,n,num,l,r,C=1;char str[20];scanf("%d",&t);while(t--){printf("Case %d:\n",C++);scanf("%d",&n);Creat(1,n,1);for(int i=1;i<=n;i++){scanf("%d",&num);UPdata(1,i,num);}while(scanf("%s",str)){if(str[0]=='E')break;else if(str[0]=='Q'){scanf("%d%d",&l,&r);query(1,l,r);printf("%d\n",ans);ans=0;}else if(str[0]=='A'){scanf("%d%d",&l,&r);UPdata(1,l,r);}else if(str[0]=='S'){scanf("%d%d",&l,&r);UPdata(1,l,-r);} /* else if(str[0]=='D')//單點查詢 { scanf("%d",&l); query(1,l,l); printf("%d\n",ans); ans = 0; }*/}}return 0;}
區間增減
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define max(a,b) (a>b)?a:b#define min(a,b) (a>b)?b:a#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1#define LL __int64const int maxn = 500100;using namespace std;#define MAX INT_MAX#define MIN INT_MINstruct node{ int l,r; LL add,sum; //add作為一個數的累加和,同時起標記的作用,即lazy數組的作用}T[300010];int a[100005]; //add必須是__int64;void putup(int id){ T[id].sum=T[2*id].sum+T[2*id+1].sum;}void putdown(int id){ if(T[id].add) //更新左右孩子 { T[2*id].add+=T[id].add; T[2*id].sum += (T[2*id].r-T[2*id].l+1)*T[id].add; T[2*id+1].add+=T[id].add; T[2*id+1].sum += (T[2*id+1].r-T[2*id+1].l+1)*T[id].add; T[id].add=0; //取消標幟 }}void creat(int l,int r,int id){ T[id].l=l; T[id].r=r; T[id].add=0; if(l==r) { T[id].sum=a[r]; return; } int mid=(l+r)>>1; creat(l,mid,2*id); creat(mid+1,r,2*id+1); putup(id);}void update(int from,int to,LL add,int id){ if(from<=T[id].l&&to>=T[id].r) { T[id].add +=add; T[id].sum += (T[id].r-T[id].l+1)*add; return; } putdown(id); if(from<=T[2*id].r) update(from,to,add,2*id); if(to>=T[2*id+1].l) update(from,to,add,2*id+1); putup(id);}LL query(int from,int to,int id){ if(from==T[id].l&&to==T[id].r) return T[id].sum; putdown(id); if(from>=T[2*id+1].l) return query(from,to,2*id+1); else if(to<=T[2*id].r) return query(from,to,2*id); else return query(from,T[2*id].r,2*id) + query(T[2*id+1].l,to,2*id+1);}int main(){ int n,m,A,B; LL add; char str[5]; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1; i<=n; i++) scanf("%d",&a[i]); creat(1,n,1); while(m--) { LL ans = 0; scanf("%s",str); if(str[0]=='C') { scanf("%d%d%I64d",&A,&B,&add); update(A,B,add,1); } else { scanf("%d%d",&A,&B); ans=query(A,B,1); printf("%I64d\n",ans); } } }}
區間替換
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define max(a,b) (a>b)?a:b#define min(a,b) (a>b)?b:a#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1#define LL __int64const int maxn = 500100;using namespace std;#define MAX INT_MAX#define MIN INT_MINstruct node{ int l,r; LL add,sum; }T[400010];int a[100005]; void putup(int id){ T[id].sum=T[2*id].sum+T[2*id+1].sum;}void putdown(int id){ if(T[id].add) { T[2*id].add= T[2*id+1].add= T[id].add; T[2*id].sum = (T[2*id].r-T[2*id].l+1)*T[id].add; T[2*id+1].sum = (T[2*id+1].r-T[2*id+1].l+1)*T[id].add; T[id].add=0; }}void creat(int l,int r,int id){ T[id].l=l; T[id].r=r; T[id].add=0; // T[id].sum = 1; if(l==r) { T[id].sum=a[r]; return; } int mid=(l+r)>>1; creat(l,mid,2*id); creat(mid+1,r,2*id+1); putup(id);}void update(int from,int to,LL add,int id){ if(from<=T[id].l&&to>=T[id].r) { T[id].add = add; T[id].sum = (T[id].r-T[id].l+1)*add; return; } putdown(id); if(from<=T[2*id].r) update(from,to,add,2*id); if(to>=T[2*id+1].l) update(from,to,add,2*id+1); putup(id);}LL query(int from,int to,int id){ if(from==T[id].l&&to==T[id].r) return T[id].sum; putdown(id); if(from>=T[2*id+1].l) return query(from,to,2*id+1); else if(to<=T[2*id].r) return query(from,to,2*id); else return query(from,T[2*id].r,2*id) + query(T[2*id+1].l,to,2*id+1);}int main(){ int n,m,A,B; LL add; char str[5]; while(~scanf("%d%d",&n,&m)) { // C++; for(int i=1; i<=n; i++) scanf("%d",&a[i]); creat(1,n,1); while(m--) { scanf("%s",str); if(str[0]=='T') { scanf("%d%d%I64d",&A,&B,&add); update(A,B,add,1); } else if(str[0]=='Q') { scanf("%d%d",&A,&B); cout<<query(A,B,1)<<endl; } } }}