1. 程式人生 > >Chapter 3. 數據結構 線段樹

Chapter 3. 數據結構 線段樹

int 區間修改 lld ref else 如果 ios 正在 step

Chapter 3. 數據結構 線段樹

Sylvia‘s I.單點修改,區間查詢.

模板:

//單點修改 區間求和 
//1操作 單點修改
//2操作 區間求和
#include<cstdio> #include<iostream> using namespace std; #define MAXN 500005 int sum[MAXN<<2]; int n,m; void PushUp(int rt){//求和 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int
rt){//建樹 if (l==r){ scanf("%d",&sum[rt]); return; } int m=l+r>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(rt); } void Update(int P,int Add,int l,int r,int rt){//單點修改 if (l==r){ sum[rt]+=Add; return; }
int m=l+r>>1; if (P<=m) Update(P,Add,l,m,rt<<1); else Update(P,Add,m+1,r,rt<<1|1); PushUp(rt); } int Query(int L,int R,int l,int r,int rt){//區間查詢 if (L<=l&&r<=R) { return sum[rt]; } int m=l+r>>1; int ret=0;
if (L<=m) ret+=Query(L,R,l,m,rt<<1); if (m<R) ret+=Query(L,R,m+1,r,rt<<1|1); return ret; } int step,x,k; int main (){ scanf("%d%d",&n,&m); build(1,n,1); for(int i=1;i<=m;i++){ scanf("%d%d%d",&step,&x,&k); if (step==1) Update(x,k,1,n,1); if (step==2) printf("%d\n",Query(x,k,1,n,1)); } return 0; }

Sylvia‘s II. 區間修改,區間查詢.

模板:參考自:bogo的線段樹模板

//1操作 乘法操作
//2操作 加法操作
//3操作 詢問區間和
//最後的結果對P取模
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAX 100003
#define LL long long 
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct Segment_Tree{
    LL sum[MAX<<2];//數組開四倍
    LL lazy1[MAX<<2],lazy2[MAX<<2];//分別為乘法標記和加法標記
    LL P;//取模
    
    void PushUp(LL rt){//更新,對左右兒子求和
      sum[rt]=sum[rt<<1]+sum[rt<<1|1];
      sum[rt]%=P;//別忘記取模
    }
    
    void build(LL l,LL r,LL rt){//建樹
        lazy1[rt]=1;//乘法標記記為1
        lazy2[rt]=0;//加法標記記為0
        if (l==r){
           scanf("%lld",&sum[rt]);
             return;
        }
        LL m=l+r>>1;
        build(lson);//左子樹
        build(rson);//右子樹
        PushUp(rt);//及時更新
        
    }
    
    void multiply (LL rt,LL x){//單乘 
        lazy2[rt]*=x;//(A[i]+lazy2[i])*lazy1[i]=A[i]*lazy1[i]+lazy2[i]*lazy1[i],所以加法標記要乘x 
        lazy2[rt]%=P;
        lazy1[rt]*=x;//乘法標記當然也要乘…… 
        lazy1[rt]%=P;
        sum[rt]*=x;//求和數組更要乘…… 
        sum[rt]%=P;
    }
    
    void Add (LL rt,LL x,LL len){//單加 ,len為區間長度 
        lazy2[rt]=(lazy2[rt]+x)%P;//加法標記加 
        sum[rt]=(sum[rt]+(x*len)%P)%P;//求和數組加 
    }
    
    void PushDown (LL l,LL r,LL rt){
        if (lazy1[rt]!=1){//如果有乘法標記 
            multiply(rt<<1,lazy1[rt]);//把標記下放到左兒子 
            multiply(rt<<1|1,lazy1[rt]);//把標記下放到右兒子 
            lazy1[rt]=1;//別忘記清除標記…… 
        }
        if (lazy2[rt]){//如果有加法標記…… 
            Add(rt<<1,lazy2[rt],(r+l>>1)-l+1);
            Add(rt<<1|1,lazy2[rt],r-(r+l>>1));
            lazy2[rt]=0;
        }
    } 
    
    void Addall(LL L,LL R,LL x,LL l,LL r,LL rt){//區間加 
        if (L<=l&&r<=R){//當前區間包含在需要查詢的區間中 
            Add(rt,x,r-l+1);
            return;
        }
        LL m=l+r>>1;
        PushDown(l,r,rt);
        if (L<=m) Addall(L,R,x,lson);//如果需查詢區間與左兒子有交集 
        if (m<R) Addall(L,R,x,rson);//如果需查詢區間與右兒子有交集 
        PushUp(rt);//及時更新 
    }
    
    void Mullall(LL L,LL R,LL x,LL l,LL r,LL rt){// 區間乘 ,與上面類似…… 
        if (L<=l&&r<=R){
            multiply(rt,x);
            return;
        }
        LL m=l+r>>1;
        PushDown(l,r,rt);//不要忘記查詢左右兒子之前先把標記下放,血的教訓…… 
        if (L<=m) Mullall(L,R,x,lson);
        if (m<R) Mullall(L,R,x,rson);
        PushUp(rt);
    }
    
    LL Query(LL L,LL R,LL l,LL r,LL rt){//區間查詢 
        if (L<=l&&r<=R){
            return sum[rt];
        }
        LL ret=0;
        LL m=l+r>>1;
        PushDown(l,r,rt);// 不要忘記下放標記 
        if (L<=m) ret=(ret+Query(L,R,lson))%P;
        if (m<R) ret=(ret+Query(L,R,rson))%P;
        return ret;    
    }
    
}Seg;
int main (){
    LL n,m,step,x,y,z;
    scanf("%lld%lld%lld",&n,&m,&Seg.P);
    Seg.build(1,n,1);//
    for (int i=1;i<=m;i++){
        scanf("%d",&step);
        switch(step){
            case 1:
                scanf("%lld%lld%lld",&x,&y,&z);
                Seg.Mullall(x,y,z,1,n,1);
                break;
            case 2:
                scanf("%lld%lld%lld",&x,&y,&z);
                Seg.Addall(x,y,z,1,n,1);
                break;
            case 3:
                scanf("%lld%lld",&x,&y);
                printf("%lld\n",Seg.Query(x,y,1,n,1));
                break;
        }
    }
    return 0;
}


活著

余華

老人和牛漸漸遠去,我聽到老人粗啞的令人感動的嗓音從遠處傳來,

他的歌聲在空曠的傍晚像風一樣飄揚,

老人唱道:

少年去遊蕩,中年想掘藏,老年做和尚。

炊煙在農舍的屋頂裊裊升起,在霞光四射的空中分散後消隱了。

女人吆喝孩子的聲音此起彼伏,一個男人挑著糞桶從我跟前走過,扁擔吱呀吱呀一路響了過去。

慢慢地,田野趨向了寧靜,四周出現了模糊,霞光逐漸退去。

我知道黃昏正在轉瞬即逝,黑夜從天而降了。

我看到廣闊的土地袒露著結實的胸膛,

那是召喚的姿態,

就像,

女人召喚著她們的兒女,土地召喚著黑夜來臨。


Sylvia

二零一七年五月十七日

Chapter 3. 數據結構 線段樹