Luogu P1438无聊的数列

洛谷 P1438无聊的数列

题目链接

点这里!


题目描述 

维护一个数列\(a_i\),支持两种操作:

  • 给出一个长度等于 \(r-l+1\)的等差数列,首项为\(k\) 公差为\(d\) 并将它对应加到\([l,r]\)范围中的每一个数上。
    即:令\(a_l=a_l+k\) \(a_{l+1}=a_{l+1}+k+d\) ... \(a_r = a_r + k + (r-l) * d\)
  • 询问数列的第\(p\)个数的值\(a_p\).


解题思路

我们可以通过等差数列的性质\(a_i - a_{i-1} = d\)联想到我们可以用差分解决这道题目
我们先定义一个差分数组d[]
将等差数列的每一项都加到\([l,r]\)范围中的每一个数上 等价于
\(d_l\) + k
\(d_i(l<i<r+1)\) + d
\(d_{r+1}\) - k + (r-l)*d
对于第二个操作,我们对差分数组求一遍前缀和就可以了
因此本题就是一个线段树的模板题


AC_CODE

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = a; i <= b; i ++ )
using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

int n, m;
int arr[N], a[N];

struct Node {
    int l, r;
    LL val, add;
}tr[N * 4];

void pushup(int u) {
    tr[u].val = tr[u << 1].val + tr[u << 1 | 1].val;
}

void pushdown(int u) {
    Node &root = tr[u], &ls = tr[u << 1], &rs = tr[u << 1 | 1];
    ls.add += root.add, ls.val += 1LL * root.add * (ls.r - ls.l + 1);
    rs.add += root.add, rs.val += 1LL * root.add * (rs.r - rs.l + 1);
    root.add = 0;
}

void build(int u, int l, int r) {
    if(l == r) {
        tr[u] = {l, r, a[l]};
    }    
    else {                 
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void update(int u, int l, int r, int d) {
    if(tr[u].l >= l && tr[u].r <= r) {
        tr[u].add += d;
        tr[u].val += 1LL * (tr[u].r - tr[u].l + 1) * d;
    }
    else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) update(u << 1, l, r, d);
        if(r > mid) update(u << 1 | 1, l, r, d);
        pushup(u);
    }
}

LL query(int u, int l, int r) {
    if(tr[u].l >= l && tr[u].r <= r) {
        return tr[u].val;
    }
    else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        LL res = 0;
        if(l <= mid) res = query(u << 1, l, r);
        if(r > mid) res += query(u << 1 | 1, l, r);
        return res;
    }
}

void solve() {
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ ) {
        cin >> arr[i];
        a[i] = arr[i] - arr[i - 1];
    }
    build(1, 1, n);

    int op, l, r, d, k;

    while(m -- ) {
        cin >> op;
        if(op == 1) {
            cin >> l >> r >> k >> d;
            update(1, l, l, k);
            if(l < r) //注意边界 (被卡了一个多小时
                update(1, l + 1, r, d);
            int p = 0 - k - (r - l) * d;
            if(r != n) //同上 qwq
                update(1, r + 1, r + 1, p);
        }
        else {
            scanf("%d", &k);
            printf("%lld\n", query(1, 1, k));
        }
    }
}
 
signed main() 
{
    solve();
    return 0;
}
posted @ 2021-08-15 19:52  ccz9729  阅读(81)  评论(1编辑  收藏  举报