1. 程式人生 > >【codevs1082】【樹狀陣列】 區間修改 區間查詢

【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]的和是多少。
pascal選手請不要使用readln讀入
輸出描述 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<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue> #include<algorithm> #include<vector> #include<cstdlib> #include<cmath> #include<ctime> #include<stack> #define INF 2100000000 #define ll long long #define clr(x) memset(x,0,sizeof(x)) #define clrmax(x) memset(x,127,sizeof(x)) #define M 200005 #define lowbit(x) (x&(-x))
#ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif using namespace std; ll tree[M],tree2[M],n,m; void add(ll *a,ll x,ll y) { for(int i=x;i<=M;i+=lowbit(i)) a[i]+=y; } ll find(ll *a,ll x) { ll ret=0; for(int i=x;i;i-=lowbit(i)) ret+=a[i]; return ret; } ll sigema(int x) { ll ret=0; ret+=x*find(tree,x)-find(tree2,x); return ret; } int main() { freopen("in.txt","r",stdin); scanf(LL,&n); int last=0; for(int i=1;i<=n;i++) { ll x; scanf(LL,&x); add(tree,i,x-last); add(tree2,i,(i-1)*(x-last)); last=x; } scanf(LL,&m); while(m--) { int a; scanf(LL,&a); if(a==1) { ll b,c,x; scanf(LL LL LL,&b,&c,&x); add(tree,b,x); add(tree,c+1,-x); add(tree2,b,x*(b-1)); add(tree2,c+1,-x*(c)); } else { ll b,c; scanf(LL LL,&b,&c); printf(LL"\n",sigema(c)-sigema(b-1)); } } return 0; }

大概就是這個樣子,如果有什麼問題,或錯誤,請在評論區提出,謝謝。