1082 線段樹練習 3【區間更新 區間查詢】【樹狀陣列】
阿新 • • 發佈:2018-12-15
題目描述 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<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define maxn 200002 using namespace std; ll c[205000][2],num[200500]; ll lowbit(ll x) { return x&(-x); } void update(ll x,ll val,ll p) { while(x<maxn) { c[x][p]+=val; x+=lowbit(x); } } ll query(ll x,ll p) { ll sum=0; while(x>0) { sum+=c[x][p]; x-=lowbit(x); } return sum; } ll solve(ll y) { ll ans; ans=(y+1)*(query(y,0))-query(y,1); return ans; } int main() { ll n,i,j,x,y,val,t,ans,op,q; ans=1; scanf("%lld",&n); memset(c,0,sizeof(c)); for(i=1;i<=n;i++) { scanf("%lld",&num[i]); update(i,num[i]-num[i-1],0); update(i,i*(num[i]-num[i-1]),1); } scanf("%lld",&q); while(q--) { scanf("%lld",&op); if(op==1) { scanf("%lld%lld%lld",&x,&y,&val);///區間更新 update(x,val,0); update(y+1,-val,0); update(x,val*x,1); update(y+1,-val*(y+1),1); } else { scanf("%lld%lld",&x,&y);///區間查詢 printf("%lld\n",(solve(y)-solve(x-1))); } } }