嘘~ 正在从服务器偷取页面 . . .

洛谷P2667 [TJOI2012] 防御 题解


洛谷P2667 [TJOI2012] 防御 题解

题目链接:P2667 [TJOI2012] 防御

题意

在一个塔防小游戏中,有很多防线。每条防线由一排 \(n\) 个独立的防御体 \([1 : n]\) 进行防御。

游戏过程中,会不断有敌人对防线进行攻击,每次攻击会指定防御体 \([l : r]\) 进行攻击力为 \(a\) 的攻击。第一防线具有护甲,护甲承受攻击后,对应的防御体所受到的伤害为攻击力,但护甲承受的伤害总量到达一定程度后就会破碎,此时防御体所受的伤害加倍。目前第一防线的力量充足,玩家致力于对后面的防线的建设,不过为确认游戏进度和第一防线的情况,玩家会不时地将鼠标移动到第一防线的某个防御体上,以查看其所受到的伤害。

输入格式

第一行,两个整数 \(n\)\(q\),分别表示防御体个数以及攻击和查询的总数。

第二行,\(n\) 个数,表示每个防御体护甲的承受能力 \(p_i\)

接下来 \(q\) 行,每行可能具有如下形式:

A l r a 表示对防御体 \(l,l+1,\cdots,r\) 进行攻击力为 \(a\) 的攻击;

Q x 表示查询防御体 \(x\) 目前所受到的伤害,初始时伤害为 \(0\)

输出格式

一行,一个整数,表示所有查询结果之和对 \({10}^9+9\) 取模的余数。

\(100 \%\) 的数据,\(1 \le n \le 10^5\)\(1 \le q \le 10^5\)\(0 \le p_i \le 10^6\)\(0 \le a \le 10^4\)

注意到 \(p_i\) 的范围不大,并且每个位置只可能被打爆一次。

因此我们可以维护区间内的护盾最小值,然后暴力更新护盾是否被打爆。

这道题维护区间和不太方便,因此我们可以直接维护区间的增量,类似与区间和的lazytag。

时间复杂度 \(\mathcal{O}(n \log nV)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
const int mod = 1e9 + 9;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))
#define ls(at) ((at) << 1)
#define rs(at) ((at) << 1 | 1)

int n, res, a[N]; char boom[N];
struct node { int mn, tag, val; } tr[N * 4];
void push_up(int at) {
    down(tr[at].mn = tr[ls(at)].mn, tr[rs(at)].mn);
}
void push_down(int at)
{
    if(!tr[at].tag) return;
    if(tr[ls(at)].mn != INF) tr[ls(at)].mn -= tr[at].tag;
    if(tr[rs(at)].mn != INF) tr[rs(at)].mn -= tr[at].tag;
    tr[ls(at)].tag += tr[at].tag; tr[rs(at)].tag += tr[at].tag; 
    tr[at].tag = 0;
}
void build(int l = 1, int r = n, int at = 1)
{
    if(l == r) { tr[at].mn = a[l] ? a[l] : INF; return; }
    int mid = (l + r) >> 1;
    build(l, mid, ls(at)); build(mid + 1, r, rs(at)); push_up(at);
}
void proc(int l, int r, int at, int k)
{
    if(l == r) {
        a[l] = a[l] - tr[at].mn + k;
        tr[at].mn = INF; boom[l] = true; return;
    }
    push_down(at); int mid = (l + r) >> 1;
    if(tr[ls(at)].mn <= k) proc(l, mid, ls(at), k);
    if(tr[rs(at)].mn <= k) proc(mid + 1, r, rs(at), k);
    push_up(at);
}
void update(int nl, int nr, int k, int l = 1, int r = n, int at = 1)
{
    if(nl <= l && r <= nr)
    {
        tr[at].val += k;
        if(tr[at].mn <= k) proc(l, r, at, k);
        if(tr[at].mn != INF) { tr[at].mn -= k, tr[at].tag += k; }
        return; 
    }
    push_down(at); int mid = (l + r) >> 1;
    if(nl <= mid) update(nl, nr, k, l, mid, ls(at));
    if(nr > mid) update(nl, nr, k, mid + 1, r, rs(at));
    push_up(at);
}
int query(int x, int l = 1, int r = n, int at = 1)
{
    if(l == r) return tr[at].val;
    push_down(at); int mid = (l + r) >> 1;
    if(x <= mid) return tr[at].val + query(x, l, mid, ls(at));
    else return tr[at].val + query(x, mid + 1, r, rs(at));
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int q; cin >> n >> q;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(build(); q--; ) {
        char op; cin >> op;
        if(op == 'A') {
            int l, r, k; cin >> l >> r >> k; update(l, r, k);
        }else if(op == 'Q') {
            int x; cin >> x;
            if(boom[x]) {
                res = (res + query(x) * 2 - a[x]) % mod;
            }else res = (res + query(x)) % mod;
        }
    }
    cout << (res + mod) % mod << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/KYD/solution-p2667


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录