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

P1438 無聊的數列

感謝所有AC

傳送門

反思

       題目思考量小,此題解關鍵在於反思。

       不管任何題目都需要在思路已經無法拓展開了才能參考題解!儘可能地保持25分鐘以上的思考(尤其是這種藍綠以上的題目)。

思路

       等差數列很容易引出差分的思路。對於一組等差數列,例如 1 3 5 7 9 來說,其差分陣列為 1 2 2 2 2 (-9) ,也就是說等差數列的差分陣列是 a d d ... d ,a 為首項,d 為公差。那麼題目中的數列可以在差分的狀態下進行區間處理,即對於單點 L 來說,需要加上 a ,對於區間 L+1 到 R 需要加上 d ,對於區間 R+1 要減去末項。如何詢問單點值?由差分的性質,可知還原陣列可以對差分陣列進行字首和,字首和不就是我們線段樹所維護的東西?對於詢問 p ,直接訪問區間 1 到 p 就可以實現單點查詢。

程式碼 

#include<iostream>
#define maxn 100007
using namespace std;
typedef long long ll;
int n, m, l, r, p, opt, a[maxn], ch[maxn], K, D;
ll t[maxn << 2], lzy[maxn << 2];
void pushup(int u)
{
    t[u] = t[u << 1] + t[(u << 1) + 1];
}
void build(int u, int l, int r)
{
    if (l == r)
        t[u] = ch[l];
    else
    {
        int m = l + r >> 1;
        build(u << 1, l, m), build((u << 1) + 1, m + 1, r);
        pushup(u);
    }
}
void maketag(int u, int len, ll x)
{
    lzy[u] += x;
    t[u] += (ll)len * x;
}
void pushdown(int u, int l, int r)
{
    int m = l + r >> 1;
    maketag(u << 1, m + 1 - l, lzy[u]);
    maketag((u << 1) + 1, r - m, lzy[u]);
    lzy[u] = 0;
}
void update(int u, int l, int r, int L, int R, ll x)
{
    if (L <= l && r <= R)
        maketag(u, r - l + 1, x);
    else if (!(l > R || r < L))
    {
        pushdown(u, l, r);
        int m = l + r >> 1;
        update(u << 1, l, m, L, R, x);
        update((u << 1) + 1, m + 1, r, L, R, x);
        pushup(u);
    }
}
ll query(int u, int l, int r, int L, int R)
{
    if (L <= l && r <= R)
        return t[u];
    else if (!(l > R || r < L))
    {
        pushdown(u, l, r);
        int m = l + r >> 1;
        return query(u << 1, l, m, L, R) + query((u << 1) + 1, m + 1, r, L, R);
    }
    else return 0;
}
void deal(int l, int r, int K, int D)
{
    update(1, 1, n, l, l, K); 
    if (l != r)
        update(1, 1, n, l + 1, r, D);
    if (r + 1 > n)
        return; 
    update(1, 1, n, r + 1, r + 1, -((ll)K + (ll)(r - l) * D));
}
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        ch[i] = a[i] - a[i - 1];
    build(1, 1, n);
    while (m--)
    {
        cin >> opt;
        if (opt == 1)
        {
            cin >> l >> r >> K >> D;
            deal(l, r, K, D);
        }
        else
        {
            cin >> p;
            ll ans = query(1, 1, n, 1, p);
            cout << ans << '\n';
        }
    }
    return 0;
}