P8563 Magenta Potion 題解

Night_Tide發表於2024-09-26

前排警告

這是較為通用,不需要腦子,但是程式碼量巨大的題解,請謹慎食用

解題思路

不知道大家做沒做過帶修改的區間最大連續子段和,這一題其實就是帶修改的區間最大連續子段積。

那麼其實做法是類似的。

我們用線段樹維護五個量:當前區間答案,區間字首最小值,區間字首最大值,區間字尾最小值,區間字尾最大值。

然後合併的時候分情況討論:

  1. 當前答案在左兒子區間內

  2. 當前答案在右兒子區間內

  3. 當前答案跨左,右兒子的區間

前兩種情況直接得,最後一種情況就是左兒子區間的一個字尾稱上右兒子區間的一個字首的積取最大值。

但是,不同與區間最大連續子段和直接簡單相加,由於負負得正,乘法最大值可以透過最大值 \(\times\) 最大值,最小值 \(\times\) 最小值,最大值 \(\times\) 最小值這幾種方式來得到,所以維護字首最小值和字尾最小值。

完整程式碼

很巨,建議自己打,加強印象。

#include<bits/stdc++.h>
#define MAXN 200010
#define lson now << 1
#define rson now << 1 | 1
#define INF 1073741825
using namespace std;
typedef long long ll;
struct sec{
    int l, r;
    ll mul;
    sec operator * (const sec &b){
        sec res;
        res.mul = this->mul * b.mul;
        res.l = min(this->l, b.l); res.r = max(this->r, b.r);
        return res;
    }
};
struct node{
    int l, r;
    sec max_pre, min_pre, max_lst, min_lst, max_res;
};
bool operator > (sec a, sec b){ return a.mul > b.mul; }
bool operator < (sec a, sec b){ return a.mul < b.mul; }
node tree[MAXN << 2];
int n, q;
int a[MAXN];
void push_up(node &now, node &ls, node &rs){
    now.max_res = max(ls.max_res, rs.max_res);
    now.max_res = max(now.max_res, ls.max_lst * rs.max_pre);
    now.max_res = max(now.max_res, ls.min_lst * rs.min_pre);
    now.max_res = max(now.max_res, ls.min_lst * rs.max_pre);
    now.max_res = max(now.max_res, ls.max_lst * rs.min_pre);
    if(ls.max_pre.r == ls.r){
        now.max_res = max(now.max_res, ls.max_pre * rs.max_pre);
        now.max_res = max(now.max_res, ls.max_pre * rs.min_pre);
    }
    if(ls.min_pre.r == ls.r){
        now.max_res = max(now.max_res, ls.min_pre * rs.min_pre);
        now.max_res = max(now.max_res, ls.min_pre * rs.max_pre);
    }
    if(rs.max_lst.l == rs.l){
        now.max_res = max(now.max_res, ls.max_lst * rs.max_lst);
        now.max_res = max(now.max_res, ls.min_lst * rs.max_lst);
    }
    if(rs.min_lst.l == rs.l){
        now.max_res = max(now.max_res, ls.min_lst * rs.min_lst);
        now.max_res = max(now.max_res, ls.max_lst * rs.min_lst);
    }
    if(now.max_res.mul >= INF) now.max_res.mul = INF;

    now.max_pre = ls.max_pre;
    if(ls.max_pre.r == ls.r){
        now.max_pre = max(now.max_pre, ls.max_pre * rs.max_pre);
        now.max_pre = max(now.max_pre, ls.max_pre * rs.min_pre);
    }
    if(ls.min_pre.r == ls.r){
        now.max_pre = max(now.max_pre, ls.min_pre * rs.min_pre);
        now.max_pre = max(now.max_pre, ls.min_pre * rs.max_pre);
    }
    if(now.max_pre.mul >= INF) now.max_pre.mul = INF;

    now.min_pre = ls.min_pre;
    if(ls.max_pre.r == ls.r){
        now.min_pre = min(now.min_pre, ls.max_pre * rs.max_pre);
        now.min_pre = min(now.min_pre, ls.max_pre * rs.min_pre);
    }
    if(ls.min_pre.r == ls.r){
        now.min_pre = min(now.min_pre, ls.min_pre * rs.min_pre);
        now.min_pre = min(now.min_pre, ls.min_pre * rs.max_pre);
    }
    if(now.min_pre.mul <= -INF) now.min_pre.mul = -INF;

    now.max_lst = rs.max_lst;
    if(rs.max_lst.l == rs.l){
        now.max_lst = max(now.max_lst, ls.max_lst * rs.max_lst);
        now.max_lst = max(now.max_lst, ls.min_lst * rs.max_lst);
    }
    if(rs.min_lst.l == rs.l){
        now.max_lst = max(now.max_lst, ls.min_lst * rs.min_lst);
        now.max_lst = max(now.max_lst, ls.max_lst * rs.min_lst);
    }
    if(now.max_lst.mul >= INF) now.max_lst.mul = INF;

    now.min_lst = rs.min_lst;
    if(rs.max_lst.l == rs.l){
        now.min_lst = min(now.min_lst, ls.max_lst * rs.max_lst);
        now.min_lst = min(now.min_lst, ls.min_lst * rs.max_lst);
    }
    if(rs.min_lst.l == rs.l){
        now.min_lst = min(now.min_lst, ls.min_lst * rs.min_lst);
        now.min_lst = min(now.min_lst, ls.max_lst * rs.min_lst);
    }
    if(now.min_lst.mul <= -INF) now.min_lst.mul = -INF;
}
void build(int now, int l, int r){
    tree[now].l = l; tree[now].r = r;
    if(tree[now].l == tree[now].r){
        tree[now].max_pre = tree[now].max_lst = tree[now].max_res = tree[now].min_pre = tree[now].min_lst = (sec){l, r, a[l]};
        return ;
    }
    int mid = (l + r) >> 1;
    build(lson, l, mid); build(rson, mid + 1, r);
    push_up(tree[now], tree[lson], tree[rson]);
}
void update(int now, int pos, int val){
    if(tree[now].l == pos && tree[now].r == pos){
        tree[now].max_pre = tree[now].max_lst = tree[now].max_res = tree[now].min_pre = tree[now].min_lst = (sec){tree[now].l, tree[now].r, val};
        return ;
    }
    int mid = (tree[now].l + tree[now].r) >> 1;
    if(pos <= mid) update(lson, pos, val);
    else update(rson, pos, val);
    push_up(tree[now], tree[lson], tree[rson]);
}
node query(int now, int l, int r){
    if(tree[now].l >= l && tree[now].r <= r){
        return tree[now];
    }
    int mid = (tree[now].l + tree[now].r) >> 1;
    if(r <= mid) return query(lson, l, r);
    else if(l > mid) return query(rson, l, r);
    else{
        node ls = query(lson, l, mid), rs = query(rson, mid + 1, r), res;
        res.l = l; res.r = r;
        push_up(res, ls, rs);
        return res;
    }
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
    build(1, 1, n);
    // int cnt = 0;
    for(int i = 1; i <= q; i++){
        int op, x, y;
        scanf("%d%d%d",&op,&x,&y);
        if(op == 1) update(1, x, y);
        else{
            ll res = max(query(1, x, y).max_res.mul, 1ll);
            if(res >= INF) printf("Too large\n");
            else printf("%lld\n",res);
        }
    }
    return 0;
}