1. 程式人生 > 實用技巧 >AcWing243一個簡單的整數問題2(樹狀陣列+差分+字首和規律)

AcWing243一個簡單的整數問題2(樹狀陣列+差分+字首和規律)

題目地址https://www.acwing.com/problem/content/244/

題目描述

給定一個長度為N的數列A,以及M條指令,每條指令可能是以下兩種之一:

1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

2、“Q l r”,表示詢問 數列中第 l~r 個數的和。

對於每個詢問,輸出一個整數表示答案。

輸入格式

第一行兩個整數N,M。

第二行N個整數A[i]。

接下來M行表示M條指令,每條指令的格式如題目描述所示。

輸出格式

對於每個詢問,輸出一個整數表示答案。

每個答案佔一行。

資料範圍

1N,M1e5,
|d|10000,
|A[i]|1000000000

題解:這是對樹狀陣列的更深一步的擴充套件:區間加、區間求和。所以需要解決兩個問題:區間加、區間和。區間加比較容易,直接差分就可以。至於區間和我們可以想辦法求出原序列a的字首和表示方法,b是原序列的差分陣列

這張圖片中的藍色的,每一行藍色的和都是一個元素a,分別表示a[1].....a[x].所以我們只需要求出a的字首和,那麼對於區間的和就顯而易見了。至於圖中的紅色是一個填補的作用,我們可以知道a的字首和就是藍色+紅色再減去紅色。首先,藍色+紅色=a[x]*(x+1),而a[x]可以由差分陣列b的字首和求出。紅色其實是i*b[i]的字首和。所以a的前x的和S[x]=b[i]的字首和*(x+1)-i*b[i]的字首和。所以查詢[l,r]=S[r]-S[l-1]

AC程式碼

#include<iostream>
#include<cstring> 
using namespace std;
const int N=1e5+10;
#define lowbit(x) (x&(-x))
#define ll long long int
ll a[N]={0},b[N]={0},c[2][N]={0},n,m;

void add(int k,int x,ll d){
    while(x<=n){
        c[k][x]+=d;
        x+=lowbit(x);
    }
}

ll sum(int
k,int x){ ll sum=0; while(x>0){ sum+=c[k][x]; x-=lowbit(x); } return sum; } ll prefix_sum(int x){ return sum(0,x)*(x+1)-sum(1,x); } int main(){ cin>>n>>m; memset(c,0,sizeof(c)); ll now=0,x; for(int i=1;i<=n;i++){ cin>>x; a[i]=x-now; now=x; } for(int i=1;i<=n;i++){ add(0,i,a[i]);//差分陣列a[i] add(1,i,i*a[i]);//差分陣列i*a[i] } char ch; ll l,r,d; while(m--){ cin>>ch; if(ch=='C'){ cin>>l>>r>>d; add(0,l,d); add(0,r+1,-d); add(1,l,l*d); add(1,r+1,(r+1)*(-d)); } else { cin>>l>>r; cout<<(prefix_sum(r)-prefix_sum(l-1))<<endl; } } return 0; }

寫於:2020/8/26 17:27