【樹狀數組區間修改區間求和】codevs 1082 線段樹練習 3

來源:互聯網
上載者:User

標籤: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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.