线段树

区间和

http://oj.61coding.cn/problem.php?cid=1025&pid=0

#include<bits/stdc++.h>
using namespace std;
 
inline int read(){//读入优化 
    char ch;
    while((ch=getchar()) <'0' || ch>'9');
     
    int res=ch-48;
    while((ch=getchar())>='0' && ch<='9')
        res = res*10+ch-48;
    return res; 
}
 
const int N=1e5+5;
int n,m;
long long sum[N*4];//数组开到n的4倍
 
void updateTree(int k,int L,int R,int p,int v){//单点修改累加 
    if(R<p || L>p) return;// p不在区间范围 
    if(L==R && L==p){// 叶子节点 并且是p 累加v 
        sum[k]+=v;
        return;
    }
    int mid=(L+R)/2;
    updateTree(k*2,L,mid,p,v);//递归左子树 
    updateTree(k*2+1,mid+1,R,p,v);//递归右子树 
    sum[k]=sum[k*2]+sum[k*2+1];//父节点=左子节点+右子节点 
}
 
long long queryTree(int k,int L,int R,int x,int y){//区间查询 
    if(y<L || x>R) return 0;//不在范围内退出 
    if(L>=x && R<=y) return sum[k];//在子范围返回当前节点数据 
    int mid=(L+R)/2; 
    long long res=0;
    res=queryTree(k*2,L,mid,x,y);//在范围一部分,递归求左子树 
    res+=queryTree(k*2+1,mid+1,R,x,y);//在范围一部分,递归求右子树
    return res;//返回左右子树和 
}
 
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int k=read(),L=read(),R=read();
        if(k==0){
            updateTree(1,1,n,L,R);
        } 
        else{
            printf("%lld\n",queryTree(1,1,n,L,R)); 
        } 
    }
    return 0;
}

A Simple Problem with Integers

http://oj.61coding.cn/problem.php?cid=1025&pid=1

#include<bits/stdc++.h>
using namespace std;

inline int get(){//优化录入 
    char c;
    int sign=1;
    while((c=getchar())<'0' || c>'9'){
        if(c=='-'){
            sign=-1;
        }
    }
    int res=c-'0';
    while((c=getchar())>='0' && c<='9'){
        res=res*10+c-'0';
    }
    return res*sign;
}

const int N=1e5+5;
int n,m,a[N];
int add[N*4];//此数组存放未及时下放更新的数据 
long long sum[N*4];//用数组存放的树 总节点数可能大于2N 

void buildTree(int k,int L,int R){//建树 
    if(L==R){//叶子节点存放对应数 
        sum[k]=a[L]; 
        return;
    }
    int mid=L+R>>1;
    buildTree(k<<1,L,mid);//左子树 
    buildTree(k<<1|1,mid+1,R);//右子树 
    sum[k]=sum[k<<1]+sum[k<<1|1];//左右子节点和存放到当前树节点 
}

void addTree(int k,int L,int R,int v){//区间加值并更新 
    add[k]+=v;//单节点增加的值 
    sum[k]+=(long long)v*(R-L+1);//区间和加到本节点 
}

void pushdown(int k,int L,int R,int mid){//标记下放 
    if(add[k]==0) return;//子节点已经增加  不在增加 
    addTree(k<<1,L,mid,add[k]);//左子节点增加 
    addTree(k<<1|1,mid+1,R,add[k]);//右子节点增加 
    add[k]=0;//本节点清零 
}

long long queryTree(int k,int L,int R,int x,int y){//区间询问 
    if(L>=x && R<=y) return sum[k];//需要查询的范围在L-R范围内 
    //不完全在范围内 
    int mid=L+R>>1;
    long long res=0;
    pushdown(k,L,R,mid);//处理当前未下传节点 
    if(x<=mid) res+=queryTree(k<<1,  L,  mid,x,y);//查询左子树 
    if(mid<y)  res+=queryTree(k<<1|1,mid+1,R,x,y);//查询右子树 
    return res; //返回左右子树和 
}

void modifyTree(int k,int L,int R,int x,int y,int v){
    //如果修改范围大于L-R范围 只增加本次k节点 不更新子节点 
    if(L>=x && R<=y) return addTree(k,L,R,v); 
    //部分范围 需要更新子节点 标记下传 
    int mid=L+R>>1;
    pushdown(k,L,R,mid);
    if(x<=mid) modifyTree(k<<1,  L,  mid,x,y,v);//更新左子节点 
    if(mid<y)  modifyTree(k<<1|1,mid+1,R,x,y,v);//更新右子节点 
    sum[k]=sum[k<<1]+sum[k<<1|1];//返回左右子节点和 
}

int main(){

    n=get(),m=get();
    for(int i=1;i<=n;i++) a[i]=get();
    buildTree(1,1,n);
    while(m--){
        char op;
        int A,B,C;
        while((op=getchar()) =='Q' || op=='C'){
            A=get(),B=get();
            cout<<"m:"<<m<<",op:"<<op<<",A:"<<A<<",B:"<<B<<endl;
            if(op=='Q') printf("%lld\n",queryTree(1,1,n,A,B));
            else modifyTree(1,1,n,A,B,get());
        }
    }
    return 0;
}

 

posted @ 2021-11-27 14:51  new-code  阅读(29)  评论(0)    收藏  举报