codevs1082

题目描述 Description

给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

 

再接下来一个正整数Q,每行表示操作的个数,

 

如果第一个数是1,后接3个正整数,

 

表示在区间[a,b]内每个数增加X,如果是2,

 

表示操作2询问区间[a,b]的和是多少。

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000

1<=q<=200000

 

先给出最基础的线段树的打法

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int n,Q,a[200005];

inline int read(){
    char ch=getchar();int k=0,f=1;
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){k=(k<<1)+(k<<3)+ch-'0';ch=getchar();}
    return k*f;
}

void add(int x,int add){
    for(;x<=n;x+=x&-x) a[x]+=add;
}

int query(int x){
    int k=0;for(;x;x-=x&-x) k+=a[x];return k; 
}

int main(){
    n=read();
    for(int i=1;i<=n;i++) add(i,read());
    Q=read();
    for(int i=1;i<=Q;i++){
        int flag=read(),x=read(),y=read();if(x>y)swap(x,y);
        if(flag==1){
            int z=read();
            add(x,(y-x+1)*z);add(y+1,-(y-x+1)*z);
        }
        else printf("%ld\n",query(y)-query(x-1));
    }
    return 0;
}

 

但打这题主要是为了理解树状数组的区间修改和区间查询

 

#include<cstdio>
#include<cctype>
using namespace std;

long long c1[200004],c2[200004],n,q;

inline long long read(){
    char ch=getchar();long long k=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)){k=(k<<1)+(k<<3)+ch-'0';ch=getchar();}
    return k;
}

void update(long long *arr,long long x,long long add){
    for(;x<=n;x+=x&-x) arr[x]+=add;
}

long long query(long long *arr,long long x){
    long long t=0;for(;x;x-=x&-x) t+=arr[x];return t;
}

int main(){
   n=read();long long las=0;
   for(long long i=1;i<=n;i++){
         long long y=read();update(c1,i,y-las);update(c2,i,(i-1)*(y-las));las=y;//i-1=n-(n-i+1)=>在前缀和中,y-las被加了(n-i+1)次,由于后来统计师算了n次,c[i]记录多算的数的大小 
   }
   q=read();
   for(long long i=1;i<=q;i++){
        long long flag=read(),l=read(),r=read();
        if(flag==1){
             long long inc=read();
             update(c1,l,inc);update(c1,r+1,-inc);//差分思想,c[i]记录差,则segma(c[1]~c[i])为数 i 的值 
             update(c2,l,(l-1)*inc);update(c2,r+1,-r*inc);//同理 l-1=n-(n-l+1) r=n-(n-(r+1)+1)
        }
    else{
        long long sum1=(l-1)*query(c1,l-1)-query(c2,l-1);
        long long sum2=r*query(c1,r)-query(c2,r);
        printf("%lld\n",sum2-sum1);
    }
   }
   return 0;
}

 

posted @ 2018-03-14 21:09  lnyzo  阅读(273)  评论(0编辑  收藏  举报