1. 程式人生 > 其它 >Luogu P1438無聊的數列

Luogu 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;
}