[線段樹模板] 區間修改 區間查詢(詳注)


輸入

每個測試點(輸入文件)有且僅有一組測試數據。

每組測試數據的第1行為一個整數N,意義如前文所述。

每組測試數據的第2行為N個整數,分別描述每種商品的重量,其中第i個整數表示標號為i的商品的重量Pi。

每組測試數據的第3行為一個整數Q,表示小Hi進行的操作數。

每組測試數據的第N+4~N+Q+3行,每行分別描述一次操作,每行的開頭均為一個屬於0或1的數字,分別表示該行描述一個詢問和一次商品的價格的更改兩種情況。對於第N+i+3行,如果該行描述一個詢問,則接下來為兩個整數Li, Ri,表示小Hi詢問的一個區間[Li, Ri];如果該行描述一次商品的價格的更改,則接下來為三個整數Li,Ri,NewP,表示標號在區間[Li, Ri]的商品的價格全部修改為NewP。

對於100%的數據,滿足N<=10^5,Q<=10^5, 1<=Li<=Ri<=N,1<=Pi<=N, 0&ltPi, NewP<=10^4。

輸出

對於每組測試數據,對於每個小Hi的詢問,按照在輸入中出現的順序,各輸出一行,表示查詢的結果:標號在區間[Li, Ri]中的所有商品的價格之和。

 

#include <iostream>
#include <cstring> 
using namespace std;
const long long maxn = 1e5;
long long a[maxn+5],sum[maxn*4+5],tag[maxn*4+5];

//樹上的每個節點都是其管轄區間的和 
void op(long long k){
    sum[k] = sum[k*2]+sum[k*2+1];
}

//建樹過程 
void build(long long l,long long r,long long k){
    if(l>r)
        return;
    if(l==r){
        sum[k] = a[l];
        tag[k] = 0;
        return;
    }
    long long mid = (l+r)/2;
    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
    op(k);
}

//下放標記到左右結點 
void pushdown(long long lenl,long long lenr,long long k){
    if(tag[k]){
        tag[k*2] = tag[k];
        tag[k*2+1] = tag[k];
        sum[k*2] = tag[k]*lenl;
        sum[k*2+1] = tag[k]*lenr;
        tag[k] = 0;
    }
}

//區間修改 
void change(long long l,long long r,long long pl,long long pr,long long k,long long val){
    if(l>r||pl>r||pr<l) //剪枝 
        return;
    if(l>=pl&&r<=pr){  //查詢區間覆蓋當前區間 
        sum[k] = val*(r-l+1); //當前結點的sum值需要修改為其覆蓋結點之和 
        tag[k] = val;  //對當前節點的修改進行標記,等到查詢時再push下去 
        return;
    }
    //查詢區間沒有覆蓋當前區間 
    long long mid = (l+r)/2;  //繼續二分查找子區間 
    pushdown(mid-l+1,r-mid,k);  //二分之前需要將當前結點的懶標記push下去,因為子節點一定會用到 
    change(l,mid,pl,pr,k*2,val);  //修改左區間 
    change(mid+1,r,pl,pr,k*2+1,val);  //修改右區間 
    op(k); //修改后求和 
}

//區間查詢 
long long query(long long l,long long r,long long ql,long long qr,long long k){
    if(l>r||ql>r||qr<l) //剪枝
        return 0;
    if(l>=ql&&r<=qr) //查詢區間覆蓋當前區間 
        return sum[k];  //當前區間和一定是答案的一部分,返回 
    //查詢區間沒有完全覆蓋當前區間
    long long mid = (l+r)/2,ans = 0;
    pushdown(mid-l+1,r-mid,k);  //push當前結點的懶標記 
    if(mid>=l)
        ans+=query(l,mid,ql,qr,k*2);  //左區間查找 
    if(mid<r)
        ans+=query(mid+1,r,ql,qr,k*2+1);  //右區間查找 
    return ans;
}

int main(){
    long long N,Q;
    scanf("%lld",&N);
    memset(a,0,sizeof(a));
    memset(sum,0,sizeof(sum));
    memset(tag,0,sizeof(tag));
    for(long long i=1;i<=N;i++){
        scanf("%lld",&a[i]);
    }
    build(1,N,1);
    scanf("%lld",&Q);
    long long type,l,r,val;
    for(long long i=0;i<Q;i++){
        scanf("%lld %lld %lld",&type,&l,&r);
        if(type==0){
            printf("%lld\n",query(1,N,l,r,1));
        }else{
            scanf("%lld",&val);
            change(1,N,l,r,1,val);
        }
    }
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM