標籤:style main sigma ons 線段 樹狀數組 max pen logs
http://codevs.cn/problem/1082/
【AC】
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=2e5+2; 5 int n; 6 ll a[maxn]; 7 ll c1[maxn]; 8 ll c2[maxn]; 9 int lowbit(int x)10 {11 return x&-x;12 }13 void add(ll *c,int k,ll val)14 {15 while(k<=n){16 c[k]+=val;17 k+=lowbit(k);18 }19 }20 ll query(ll *c,int k)21 {22 ll ans=0;23 while(k)24 {25 ans+=c[k];26 k-=lowbit(k);27 }28 return ans;29 }30 ll solve(int x)31 {32 ll ans=0;33 ans+=x*query(c1,x);34 ans-=query(c2,x);35 return ans; 36 }37 ll solve(int x,int y)38 {39 return solve(y)-solve(x-1); 40 }41 int main()42 {43 while(~scanf("%d",&n))44 {45 a[0]=0;46 for(int i=1;i<=n;i++)47 {48 scanf("%I64d",&a[i]);49 // cout<<a[i]<<endl;50 add(c1,i,a[i]-a[i-1]);51 add(c2,i,(i-1)*(a[i]-a[i-1]));52 } 53 int q;54 scanf("%d",&q);55 int tp;56 while(q--)57 {58 scanf("%d",&tp);59 if(tp==1)60 {61 int x,y;ll val;62 scanf("%d%d%I64d",&x,&y,&val); 63 add(c1,x,val);64 add(c1,y+1,-val);65 add(c2,x,1ll*(x-1)*val);66 add(c2,y+1,-1ll*y*val);67 }68 else69 {70 int x,y;71 scanf("%d%d",&x,&y);72 ll ans=solve(x,y);73 printf("%I64d\n",ans);74 }75 }76 }77 return 0;78 }View Code
【原理】
原理是用了差分數組,轉載自http://www.cnblogs.com/boceng/p/7222751.html
樹狀數組時間複雜度為O(MlogN), 實際用的時候優於線段樹,且寫得少。
神牛是引入了差分數組,要維護的差分數組ks[i] = a[i] - a[i-1]; 可以容易得到a[i] = ks[1] + ks[2] + ... + ks[i]; 即前i項和,為方便記為sigma(ks, i),已經可以看到樹狀數組的影子了,所以求區間和隨之得到
a[1] + a[2] + .. + a[n] = sigma(ks, 1) + sigma(ks, 2) + ... + sigma(ks, n);
= n*ks[1] + (n-1)*ks[2] + ... + 2*ks[n-1] + 1*ks[n];
= n*(ks[1] + ks[2] +...+ ks[n]) - (0*ks[1] + 1*ks[2] + ... + (n-1)*ks[n]);
所以可以得到 sum[n] =n * sigma(ks, n) - (0*ks[1] + 1*ks[2] + ... + (n-1)*ks[n]);
令jk[i] = (i-1) * ks[i];
則 sum[n] = n * sigma(ks, n) - sigma(jk, n);
之後便是構造兩個樹狀數組;
1 int lowbit(int k){ 2 return k & -k; 3 } 4 void add(int n, int *c, int k, int va){ 5 while(k <= n){ 6 c[k] += va; 7 k += lowbit(k); 8 } 9 }10 11 //-------------------------------------12 13 for(i = 1; i <= n; ++i){14 add(n, c1, i, jk[i]-jk[i-1]);15 add(n, c2, i, (i-1)*(jk[i]-jk[i-1]));16 }View Code
然後進行查詢求和
1 int sigma(int *c, int k){ 2 int sum = 0; 3 while(k){ 4 sum += c[k]; 5 k -= lowbit(k); 6 } 7 return sum; 8 } 9 int getSum(int s, int t){10 return (t*sigma(c1, t)-sigma(c2, t)) - ((s-1)*sigma(c1, s-1)-sigma(c2, s-1));11 }View Code
進行單點查詢時,只需兩個參數均傳入該點。
在進行區間更新的時候,神牛市通過兩次維護c1,兩次c2得到的,但本人推測了幾種情況,都不能很好的解釋這麼做的原因,
1 void update(int s, int t, int va){2 add(c1, s, va);3 add(c1, t+1, -va);4 add(c2, s, va*(s-1));5 add(c2, t+1, -va*t);6 }View Code
【樹狀數組區間修改區間求和】codevs 1082 線段樹練習 3