首页 > 其他分享 >P8563 Magenta Potion 题解

P8563 Magenta Potion 题解

时间:2024-09-26 18:14:47浏览次数:10  
标签:pre Potion min 题解 lst ls max Magenta now

前排警告

这是较为通用,不需要脑子,但是代码量巨大的题解,请谨慎食用

解题思路

不知道大家做没做过带修改的区间最大连续子段和,这一题其实就是带修改的区间最大连续子段积。

那么其实做法是类似的。

我们用线段树维护五个量:当前区间答案,区间前缀最小值,区间前缀最大值,区间后缀最小值,区间后缀最大值。

然后合并的时候分情况讨论:

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

标签:pre,Potion,min,题解,lst,ls,max,Magenta,now
From: https://www.cnblogs.com/NightTide/p/18434020

相关文章

  • P8564 ρars/ey 题解
    显然树上背包。首先一眼会想到的状态:\(dp_{i,j}\)表示\(i\)的子树最后剩下\(j\)个结点的最小代价。然而开始写会发现这并不好DP。于是我们换一个想法:\(dp_{i,j}\)表示\(i\)的子树删去\(j\)个结点的最小代价。则有转移方程:\[dp_{i,j}=\min_{v\inson(i)}\{dp_{i......
  • 题解:UVA1456 Cellular Network
    UVA1456CellularNetwork题解夭寿了!30行写完紫题了!更新:已联系管理员修改难度,现在是绿题题意很简单,不再赘述。首先一个小贪心,将概率\(u​\)进行从大到小的排序,优先查看概率大的区域,显然这样能够保证访问数量期望最小。接着考虑如何将区域分组。一个显而易见的思路是动态......
  • 题解:CF437B The Child and Set
    CF437BTheChildandSet题解这题目就一个问题。啥是\(\operatorname{lowbit}\)?\(\operatorname{lowbit}(x)\)是指\(x\)的二进制表示中最低位的\(1\)所表示的值。例如\((14)_{10}=(1110)_2\),其中最低位的\(1\)在第二位,表示\((2)_{10}\),即\(\operatorname{lo......
  • 题解:P4288 [SHOI2014] 信号增幅仪
    很好一题目,使我的最小圆覆盖旋转。先假设\(p=1\)。这是最简单的情况。这个时候我们就得到了一个裸的最小圆覆盖。当\(p\not=1\),但是\(a=0\)的时候。圆就变成了对称轴与坐标轴平行的椭圆,运用高中知识仿射一下,又回到了最小圆覆盖。在一般的情况下,我们先通过坐标的旋转......
  • 《超级机器人大战30》缺少roboex32.dll启动遇阻怎么办?轻松应对《超级机器人大战30》ro
    当《超级机器人大战30》因缺少roboex32.dll文件而启动遇阻时,可以尝试以下几种解决方案来轻松应对这一问题:一、下载并替换缺失的DLL文件寻找可靠来源:首先,需要在互联网上找到可靠的roboex32.dll文件下载源。建议访问官方网站、微软官方下载中心或知名的软件下载站点,以确保下载......
  • AT_arc176_e [ARC176E] Max Vector 题解
    发现数据范围很小,考虑最小割。先对题面做一个转化:构造两个序列\(X=(X_1,X_2,\dots,X_N),Y=(Y_1,Y_2,\dots,Y_N)\)最小化\(\sumX_i+Y_i\),有\(M\)个限制,每个限制有一个序列\(A_1,A_2,\dots,A_n\),需要满足\(\foralli,X_i\geA_i\)或者\(\foralli,Y_i\geA_i\)。考虑怎......
  • 1. 两数之和题解
    题目描述[!NOTE]总结:找出整数数组中两数之后等于目标值的两个数,然后返回其下标给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素......
  • 「FJWC2020Day5-zzq」rng 题解
    题意简述一个长度为\(n\)的实数序列\(a_i\),其中\(a_i\)为\([l_i,r_i]\)中独立均匀随机选取的实数。你只能通过交换相邻两个数,使得\(a_i\)单调不降。你需要求出你最少操作次数的期望,对\(M=998244353\)取模。\(1\leqn\leq10^6\),\(0\leql_i\ltr_i\leq10^{1......
  • 留学期间学业常见问题解决办法,包括不能毕业的状况
    留学期间学业常见问题解决办法,包括不能毕业的状况【国外留学期间,遇到考试挂科的情况,影响了毕业,该怎么办?】考试挂科是一个很常见的现象,而国外院校,因为每个学校的规定不同,有的学校学生有补考机会,但是有的学校如果学生考试挂科情况很严重,或许就没有补考的机会了。这都没关系,重要的是,你......
  • 题解:P10104 [GDKOI2023 提高组] 异或图
    \(\text{Link}\)本题属于集合划分容斥,更多关于集合划分容斥的信息可观看详细揭秘:集合划分容斥的容斥系数。题意给定一个\(n\)个点\(m\)条边的图以及一个长为\(n\)的序列\(a_{1\dotsn}\),有一常数\(C\),你需要求出有多少序列\(b_{1\dotsn}\)满足\(0\leb_i\lea_i\)......