1. 程式人生 > 其它 >P2357 守墓人

P2357 守墓人

題面

在一個荒涼的墓地上,有一個令人尊敬的守墓人, 他看守的墓地從來沒有被盜過, 所以人們很放心的把自己的先人的墓安頓在他那

守墓人能看好這片墓地是必然而不是偶然……

因為……守墓人懂風水 0.0

他把墓地分為主要墓碑和次要墓碑, 主要墓碑只能有 \(1\) 個, 守墓人把他記為 \(1\) 號, 而次要墓碑有 \(n-1\) 個,守墓人將之編號為 \(2,3\dots n\),所以構成了一個有 \(n\) 個墓碑的墓地。

而每個墓碑有一個初始的風水值,這些風水值決定了墓地的風水的好壞,所以守墓人需要經常來查詢這些墓碑。

善於運用風水的守墓人,通過一次次逆天改命,使得自己擁有了無限壽命,沒人知道他活了多久。這天,你幸運的拜訪到了他,他要求你和他共同見證接下來幾年他的戰果,但不過他每次統計風水值之和都需要你來幫他計算,算錯了他會要你命 QAQ

風水也不是不可變,除非遭遇特殊情況,已知在接下來的 \(2147483647\) 年裡,會有 \(n\) 次災難,守墓人會有幾個操作:

  1. \([l,r]\) 這個區間所有的墓碑的風水值增加 \(k\)

2.將主墓碑的風水值增加 \(k\)

3.將主墓碑的風水值減少 \(k\)

4.統計 \([l,r]\) 這個區間所有的墓碑的風水值之和

5.求主墓碑的風水值

上面也說了,很多人會把先人的墓安居在這裡,而且守墓人活了很多世紀→_→,墓碑的數量會多的你不敢相信= =

守墓人和善的邀請你幫他完成這些操作,要不然哪天你的旅館爆炸了,天上下刀子.....

為了活命,還是幫他吧

輸入格式

第一行,兩個正整數 \(n,f\)

表示共有 \(n\) 塊墓碑,並且在接下來的 $2147483647 $年裡,會有 \(f\) 次世界末日

第二行,\(n\) 個正整數,表示第 \(i\) 塊墓碑的風水值

接下來 \(f\) 行,每行都會有一個針對世界末日的解決方案,如題所述,標記同題

輸出格式

輸出會有若干行,對 \(4\)\(5\) 的提問做出回答

提示說明

\(20\%\) 的資料滿足:\(1\leq n\leq 100\)

\(50\%\) 的資料滿足:\(1\leq n\leq 6000\)

\(100\%\) 的資料滿足:\(1\leq n,f\leq 2 \times 10^5\),答案不超過 64 位整數。

思路

這道題線段樹裸題。

我線段樹沒有建樹調了好久,WA了好久

程式碼

#include <bits/stdc++.h>
#define int long long
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
using namespace std;

const int SIZE = 2e5 + 5;
struct node{
    int sum, tag;
    node(){
        tag=0;
        sum=0;
    }
} t[SIZE << 2];

int a[SIZE];

void pushup(int i) {
    t[i].sum = t[ls].sum + t[rs].sum;
}

void pushdown(int i, int l, int r) {
    
        t[ls].tag += t[i].tag;
        t[rs].tag += t[i].tag;
        t[ls].sum += (mid - l + 1) * t[i].tag;
        t[rs].sum += (r - mid) * t[i].tag;
        t[i].tag = 0;
    
}

void build(int i, int l, int r) {
    if (l == r) {
        t[i].sum = a[l];
        return;
    }
    build(ls, l, mid);
    build(rs, mid + 1, r);
    pushup(i);
}

void update(int ql, int qr, int v, int i, int l, int r) {
    if (ql <= l && r <= qr) {
        t[i].sum += (r - l + 1) * v;
        t[i].tag += v;
        return;
    }
    pushdown(i, l, r);
    if (mid >= ql) {
        update(ql, qr, v, ls, l, mid);
    }
    if (mid < qr) {
        update(ql, qr, v, rs, mid + 1, r);
    }
    pushup(i);
}

int query(int ql, int qr, int i, int l, int r) {
    if (ql <= l && r <= qr) {
        return t[i].sum;
    }
    pushdown(i, l, r);
    int result = 0;
    if (mid >= ql) {
        result += query(ql, qr, ls, l, mid);
    }
    if (mid < qr) {
        result += query(ql, qr, rs, mid + 1, r);
    }
    return result;
}

int n, f;

signed main() {
    cin >> n >> f;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    build(1,1,n);
    while (f--) {
        int op, l, r, k;
        cin >> op;
        if (op == 1) {
            cin >> l >> r >> k;
            update(l, r, k, 1, 1, n);
        }
        if (op == 2) {
            cin >> k;
            update(1, 1, k, 1, 1, n);
        }
        if (op == 3) {
            cin >> k;
            update(1, 1, -k, 1, 1, n);
        }
        if (op == 4) {
            cin >> l >> r;
            cout << query(l, r, 1, 1, n) << endl;
        }
        if (op == 5) {
            cout << query(1, 1, 1, 1, n) << endl;
        }
    }
    return 0;
}