1. 程式人生 > >線段樹總結(單點更新,區間更新,區間求和,區間求最值)

線段樹總結(單點更新,區間更新,區間求和,區間求最值)

注:每個功能在程式碼中有註釋,具體詳解可自己輸出測試

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 400010
#define LL long long
LL sum[N],lazy[N];
///向上更新求和
void pushUp(int root){
    sum[root]=sum[root<<1] + sum[(root<<1)+1];
}
///向下更新求和
void pushDown(int root,int len){
    lazy[root<<1]+=lazy[root];
    lazy[(root<<1)+1]+=lazy[root];
    sum[root<<1]+=(len-(len>>1))*lazy[root];
    sum[(root<<1)+1]+=(len>>1)*lazy[root];
    lazy[root]=0;
}
///建樹
void build(int l,int r,int root){
    lazy[root]=0;
    if(l==r){
        scanf("%I64d",&sum[root]);
        return;
    }
    int m = (l+r)>>1;
    build(l,m,root<<1);
    build(m+1,r,(root<<1)+1);
    pushUp(root);
}
///在(l,r)區間內,根節點為root,將(L,R)區間的每個數 +c
void update(int L,int R,long long c,int l,int r,int root){
   if(L<=l&&R>=r){
        lazy[root]+=c;
        sum[root]+=c*(r-l+1);
        return;
    }
    if(lazy[root]) pushDown(root,r-l+1);
    int m = (l+r)>>1;
    if(L<=m) update(L,R,c,l,m,root<<1);
    if(R>m) update(L,R,c,m+1,r,(root<<1)+1);
    pushUp(root);
}
///在(l,r)區間內,根節點為root,求(L,R)區間的數的和
LL query(int L,int R,int l,int r,int root){
    if(L<=l&&R>=r) return sum[root];
    if(lazy[root]){
        pushDown(root,r-l+1);
    }
    int m=(l+r)>>1;
    LL ans=0;
    if(L<=m) ans+=query(L,R,l,m,root<<1);
    if(R>m) ans+=query(L,R,m+1,r,(root<<1)+1);
    return ans;
}
int main(){
    int n,q,a,b;
    long long c;
    char ch;
    scanf("%d%d",&n,&q);
        build(1,n,1);
        while(q--){
            getchar();
            scanf("%c",&ch);
            if(ch=='Q'){
                scanf("%d%d",&a,&b);
                printf("%I64d\n",query(a,b,1,n,1));
            }else{
                scanf("%d%d%I64d",&a,&b,&c);
                update(a,b,c,1,n,1);
            }

        }
    return 0;
}


2:區間更新與區間求最值

注:最大值最小值函式經測試都具有可行性,可自行測試

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define N 4000001
#define INF 0x3f3f3f3f
int Min[N];
int Max[N];
int lazy[N];
bool vis[N];
///向上更新最值
void PushUp(int root){
    Min[root]=min(Min[root<<1],Min[(root<<1)+1]);
    Max[root]=max(Max[root<<1],Max[(root<<1)+1]);
}
///向下更新最值
void PushDown(int root,int c){
    Min[root<<1]=Min[(root<<1)+1]=lazy[root];
    Max[root<<1]=Max[(root<<1)+1]=lazy[root];
    vis[root<<1]=vis[(root<<1)+1]=true;
    lazy[root<<1]=lazy[(root<<1)+1]=lazy[root];
    vis[root]=false;
}
///建樹,根節點為root,區間為(l,r)
void build(int l,int r,int root){
    if(l==r){
        scanf("%d",&Min[root]);
        Max[root]=Min[root];
        return;
    }
    int m = (l+r)>>1;
    build(l,m,root<<1);
    build(m+1,r,(root<<1)+1);
    PushUp(root);
}
///在(l,r)區間內,根節點為root,求(L,R)區間的最小值
int getMin(int L,int R,int l,int r,int root){
  //  if(vis[root]) return Min[root];
    if(L<=l&&R>=r) return Min[root];
    if(vis[root]) PushDown(root,lazy[root]);
    int m = (l+r)>>1,ret=INF;
    if(L<=m) ret = min(ret,getMin(L,R,l,m,root<<1));
    if(R>m) ret = min(ret,getMin(L,R,m+1,r,(root<<1)+1));
    return ret;
}
///在(l,r)區間內,根節點為root,求(L,R)區間的最大值
int getMax(int L,int R,int l,int r,int root){
    //if(vis[root]) return Max[root];
    if(L<=l&&R>=r) return Max[root];
    if(vis[root]) PushDown(root,lazy[root]);
    int m = (l+r)>>1,ret=0;
    if(L<=m) ret = max(ret,getMax(L,R,l,m,root<<1));
    if(R>m) ret = max(ret,getMax(L,R,m+1,r,(root<<1)+1));
    return ret;
}
///在(l,r)區間內,根節點為root,將(L,R)區間的數更新為 c
void update(int L,int R,int c,int l,int r,int root){
    if(L<=l&&R>=r){
        Min[root]=Max[root]=c;
        lazy[root]=c;
        vis[root]=true;
        return ;
    }
    if(vis[root]) PushDown(root,c);
    int m = (l+r)>>1;
    if(L<=m) update(L,R,c,l,m,root<<1);
    if(R>m) update(L,R,c,m+1,r,(root<<1)+1);
    PushUp(root);
}
int main(){
    int n,m,a,b,c,t;
    while(scanf("%d",&n)!=EOF){
        memset(vis,false,sizeof(vis));
        build(1,n,1);
        scanf("%d\n",&m);
        while(m--){
            scanf("%d",&t);
            if(t==0){
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,c,1,n,1);
            }else{
                scanf("%d%d",&a,&b);
                printf("%d\n",getMin(a,b,1,n,1));
            }
        }
    }
    return 0;
}


#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define N 4000001
#define INF 0x3f3f3f3f
int Min[N];
int Max[N];
int lazy[N];
bool vis[N];
///向上更新最值
void PushUp(int root){
    Min[root]=min(Min[root<<1],Min[(root<<1)+1]);
    Max[root]=max(Max[root<<1],Max[(root<<1)+1]);
}
///向下更新最值
void PushDown(int root,int c){
    Min[root<<1]=Min[(root<<1)+1]=lazy[root];
    Max[root<<1]=Max[(root<<1)+1]=lazy[root];
    vis[root<<1]=vis[(root<<1)+1]=true;
    lazy[root<<1]=lazy[(root<<1)+1]=lazy[root];
    vis[root]=false;
}
///建樹,根節點為root,區間為(l,r)
void build(int l,int r,int root){
    if(l==r){
        scanf("%d",&Min[root]);
        Max[root]=Min[root];
        return;
    }
    int m = (l+r)>>1;
    build(l,m,root<<1);
    build(m+1,r,(root<<1)+1);
    PushUp(root);
}
///在(l,r)區間內,根節點為root,求(L,R)區間的最小值
int getMin(int L,int R,int l,int r,int root){
  //  if(vis[root]) return Min[root];
    if(L<=l&&R>=r) return Min[root];
    if(vis[root]) PushDown(root,lazy[root]);
    int m = (l+r)>>1,ret=INF;
    if(L<=m) ret = min(ret,getMin(L,R,l,m,root<<1));
    if(R>m) ret = min(ret,getMin(L,R,m+1,r,(root<<1)+1));
    return ret;
}
///在(l,r)區間內,根節點為root,求(L,R)區間的最大值
int getMax(int L,int R,int l,int r,int root){
    //if(vis[root]) return Max[root];
    if(L<=l&&R>=r) return Max[root];
    if(vis[root]) PushDown(root,lazy[root]);
    int m = (l+r)>>1,ret=0;
    if(L<=m) ret = max(ret,getMax(L,R,l,m,root<<1));
    if(R>m) ret = max(ret,getMax(L,R,m+1,r,(root<<1)+1));
    return ret;
}
///在(l,r)區間內,根節點為root,將(L,R)區間的數更新為 c
void update(int L,int R,int c,int l,int r,int root){
    if(L<=l&&R>=r){
        Min[root]=Max[root]=c;
        lazy[root]=c;
        vis[root]=true;
        return ;
    }
    if(vis[root]) PushDown(root,c);
    int m = (l+r)>>1;
    if(L<=m) update(L,R,c,l,m,root<<1);
    if(R>m) update(L,R,c,m+1,r,(root<<1)+1);
    PushUp(root);
}
int main(){
    int n,m,a,b,t;
    char c;
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(vis,false,sizeof(vis));
        build(1,n,1);
        while(m--){
            getchar();
            scanf("%c%d%d",&c,&a,&b);
            if(c=='U'){
                update(a,a,b,1,n,1);
            }else{
                printf("%d\n",getMax(a,b,1,n,1));
            }
        }
    }
    return 0;
}