E - Sum of Subarrays 解説 by physics0523


過剰な log\log が付きますが、 segment tree で解くこともできます。
区間和 k=lrAk\sum_{k=l}^{r} A_k を累積和を使って Br+1BlB_{r+1} - B_{l} という形に変形すると、 BB の連続する区間を segment tree に乗せやすくなります。

segtree のモノイドとして、以下のものを持っています。以下の情報があれば求解するのに十分です。

  • 区間内の BkB_k の総和 valval
  • 区間の長さ lenlen
  • 区間内での答え resres

実装例 (C++):

Copy
  1. #include<bits/stdc++.h>
  2. #include<atcoder/all>
  3. using namespace std;
  4. using namespace atcoder;
  5. using ll=long long;
  6. typedef struct{
  7. ll val;
  8. ll len;
  9. ll res;
  10. }S;
  11. S e(){ return {0,0,0}; }
  12. S op(S l,S r){
  13. S res;
  14. res.val=l.val+r.val;
  15. res.len=l.len+r.len;
  16. res.res=l.res+r.res;
  17. res.res+=l.len*r.val;
  18. res.res-=l.val*r.len;
  19. return res;
  20. }
  21. int main(){
  22. ll n,q;
  23. cin >> n >> q;
  24. vector<ll> a(n);
  25. for(auto &nx : a){cin >> nx;}
  26. vector<S> ini(n+1);
  27. S cur={0,1,0};
  28. ini[0]=cur;
  29. for(ll i=1;i<=n;i++){
  30. cur.val+=a[i-1];
  31. ini[i]=cur;
  32. }
  33. segtree<S,op,e> seg(ini);
  34. vector<ll> res;
  35. while(q>0){
  36. q--;
  37. ll l,r;
  38. cin >> l >> r;
  39. l--;
  40. cout << seg.prod(l,r+1).res << "\n";
  41. }
  42. return 0;
  43. }
#include<bits/stdc++.h>
#include<atcoder/all>

using namespace std;
using namespace atcoder;
using ll=long long;

typedef struct{
  ll val;
  ll len;
  ll res;
}S;

S e(){ return {0,0,0}; }
S op(S l,S r){
  S res;
  res.val=l.val+r.val;
  res.len=l.len+r.len;
  res.res=l.res+r.res;
  res.res+=l.len*r.val;
  res.res-=l.val*r.len;
  return res;
}

int main(){
  ll n,q;
  cin >> n >> q;
  vector<ll> a(n);
  for(auto &nx : a){cin >> nx;}
  vector<S> ini(n+1);
  S cur={0,1,0};
  ini[0]=cur;
  for(ll i=1;i<=n;i++){
    cur.val+=a[i-1];
    ini[i]=cur;
  }
  segtree<S,op,e> seg(ini);
  vector<ll> res;
  while(q>0){
    q--;
    ll l,r;
    cin >> l >> r;
    l--;
    cout << seg.prod(l,r+1).res << "\n";
  }
  return 0;
}

投稿日時:
最終更新:



2026-08-01 (土)
09:51:51 +09:00