zoukankan      html  css  js  c++  java
  • 【[BJOI2018]链上二次求和】

    一道挺好的数据结构题。
    先用数学式子把题目里要求的答案表示出来,设(S_i=sum_{j=1}^{i}a_j)

    [ ext{ans}=sum_{i=l}^{r}sum_{j=i}^{n}S_j-S_{j-i} ]

    [ ext{ans=}sum_{j=l}^{r}(sum_{j=i}^{n}S_j-sum_{j=0}^{n-i}S_j) ]

    然后设(SS_i=sum_{j=1}^{i}S_i)
    于是

    [ ext{ans}=sum_{j=l}^{r}(SS_n-SS_{i-1}-SS_{n-i}) ]

    [ ext{ans}=(r-l+1)SS_{n}-sum_{i=l-1}^{r-1}SS_i-sum_{i=n-r}^{n-l}SS_i ]

    这个东西可以直接用线段树维护,复杂度一个( ext{log}),接着考虑修改。
    如果修改的区间是([l,r,d])的话,那么它对(SS_i(iin [1,n]))的影响就是:
    (1:iin[1,l)),无影响。
    (2:iin[l,r]),因为(a_i(iin[l,r]))增加了( ext{d}),所以(S_i(iin[l,r]))相当于增加了(i-l+1)( ext{d}),所以(SS_i)就增加了(sum_{j=1}^{i}d*(j-l+1))
    (3:i in(r,n]),我们可以想象一下,在(>d)之后(SS_i)的增加就固定了,所以再加上前面的贡献就是(sum_{j=l}^{r}d*(j-l+1)+(i-r)*d*(r-l+1))
    然后可以把这两个式子化成一个关于(i)的二次函数形式(这一步上了小学的人应该都会,这里就略去了),可以在线段树上维护这个二次函数的( ext{a,b,c})值,这道题就做完了。
    所以除了代码细节多多多多多多多多之外也没有什么特别恶心的地方。(顺便提个醒,这题的屑数据还会出现(l>r),要判掉)。

    My Code

    #include <bits/stdc++.h> 
    
    typedef long long ll;
    const int mod = 1e9 + 7;
    const int inv2 = 5e8 + 4;
    const int N = 2e5 + 10;
    int n, m, i, j, k;  
    int s[N], ss[N], sum[N << 2], a[N];
    int sa[N << 2], sb[N << 2], sc[N << 2];
    inline int add(int a, int b) { ll c = a + b; if (c < 0) c += mod; return c >= mod ? c - mod : c; }
    struct tag {
      int a, b, c; 
      tag() { a = b = c = 0; } 
      tag(int _a, int _b, int _c) { a = _a, b = _b, c = _c; }
      inline void init() {
        a = add(a, 0);
        b = add(b, 0);
        c = add(c, 0);
      }
    } laz[N << 2], mdy;
    inline void down(int u, tag t) { 
      int a = t.a, b = t.b, c = t.c;
      sum[u] = add(add(add(sum[u], 1ll * a * sa[u] % mod), 1ll * b * sb[u] % mod), 1ll * sc[u] * c % mod);  
      laz[u].a = add(laz[u].a, a); 
      laz[u].b = add(laz[u].b, b);
      laz[u].c = add(laz[u].c, c);  
    }
    inline void push_down(int u) {
      if (laz[u].a || laz[u].b || laz[u].c) {
        down(u << 1, laz[u]);
        down(u << 1 | 1, laz[u]);
        laz[u] = tag(0, 0, 0);
      }
    }
    void build(int l, int r, int u) {
      if (l == r) {
        sum[u] = ss[l], sc[u] = 1, sb[u] = l, sa[u] = 1ll * l * l % mod;
        return;
      }
      int mid = (l + r) >> 1;
      build(l, mid, u << 1);
      build(mid + 1, r, u << 1 | 1);
      sum[u] = add(sum[u << 1], sum[u << 1 | 1]);
      sa[u] = add(sa[u << 1], sa[u << 1 | 1]);
      sb[u] = add(sb[u << 1], sb[u << 1 | 1]);
      sc[u] = add(sc[u << 1], sc[u << 1 | 1]);
      return;
    }
    void modify(int ml, int mr, int l, int r, int u) {
      if (ml <= l && r <= mr) { down(u, mdy); return; }
      int mid = (l + r) >> 1;
      push_down(u);    
      if (ml <= mid) modify(ml, mr, l, mid, u << 1);
      if (mid < mr)  modify(ml, mr, mid + 1, r, u << 1 | 1);
      sum[u] = add(sum[u << 1], sum[u << 1 | 1]); 
    }
    int query(int ql, int qr, int l, int r, int u) {    
      if (ql > qr) return 0; if (ql > r || qr < l) return 0;  
      if (ql <= l && r <= qr) return sum[u];
      push_down(u);
      int mid = (l + r) >> 1, res = 0;
      if (ql <= mid) res = add(res, query(ql, qr, l, mid, u << 1));
      if (mid < qr)  res = add(res, query(ql, qr, mid + 1, r, u << 1 | 1));
      return res;
    }
    
    int main() {
     scanf("%d %d", &n, &m);
      for (int i = 1; i <= n; i++) scanf("%d", a + i), s[i] = add(s[i - 1], a[i]), ss[i] = add(ss[i - 1], s[i]);
      build(1, n, 1);
      for (int i = 1, opt, l, r, z; i <= m; i++) {
        scanf("%d %d %d", &opt, &l, &r);
        if (l > r) std::swap(l, r);  
        if (opt == 1) {
          scanf("%d", &z); int len = r - l + 1, a = (ll)z * inv2 % mod;
          mdy = tag(a, (ll)a * (3 - 2 * l + mod) % mod,((ll)l * l - 3 * l + 2) % mod * a % mod);
          modify(l, r, 1, n, 1);   
          if (r == n) continue;
          mdy = tag(0, (ll)len * z % mod, ((ll)len * (len + 1) / 2 % mod * z % mod - (ll)len * r % mod * z % mod + mod) % mod);
          modify(r + 1, n, 1, n, 1);      
        } else {
          int len = r - l + 1;
          ll ans = ((ll)len * query(n, n, 1, n, 1) % mod - query(std::max(l - 1, 1), r - 1, 1, n, 1) + mod - query(std::max(n - r, 1), n - l, 1, n, 1) + mod) % mod;
          printf("%lld
    ", ans);      
        }
      }
      return 0;
    }
    
  • 相关阅读:
    Python开发【第二十一篇】:Web框架之Django【基础】
    梳理
    Python Day15 jQuery
    day12 html基础
    Python day11 Mysql
    锻炼马甲线
    第一章:软件性能测试基本概念
    第4关—input()函数
    第3关—条件判断与嵌套
    第2关—数据类型与转换
  • 原文地址:https://www.cnblogs.com/Sai0511/p/12389722.html
Copyright © 2011-2022 走看看