首页 > 其他分享 >NC15162 小H的询问

NC15162 小H的询问

时间:2023-05-02 22:34:13浏览次数:44  
标签:lmx NC15162 int 询问 leq rmx 区间 sum

题目链接

题目

题目描述

小H给你一个数组 \(a\) ,要求支持以下两种操作:

  1. 0 l r \((1 \leq l \leq r \leq n)\),询问区间 \([l,r]\) 中权值和最大的有效子区间的权值和,一个子区间被认为是有效的当且仅当这个子区间中没有两个相邻的偶数或者奇数。

  2. 1 x v \((1 \leq x \leq n,-10^9 \leq v \leq 10^9)\) ,将 \(a[x]\) 的值修改为 \(v\) 。

输入描述

第一行读入两个正整数 \(n,m(1 \leq n,m \leq 10^5)\) 第二行读入 \(n\) 个整数,第 \(i\) 个表示 \(a[i](-10^9 \leq a[i] \leq 10^9)\) 接下来 \(m\) 行,每行三个数表示操作,描述见题目描述。

输出描述

输出每个询问的答案。

示例1

输入

10 10
-9 -8 -8 -8 2 -7 -5 2 2 3 
0 3 5
0 4 4
0 2 4
1 6 6
1 1 6
1 5 9
0 1 2
1 5 -8
0 2 4
1 3 -2

输出

2
-8
-8
6
-8

题解

知识点:线段树。

见到这种连续段最大值的,先维护三个信息,区间有效最大值 \(mx\) 、区间左端点开始的有效最大值 \(lmx\) 、区间右端点开始的有效最大值 \(rmx\) ,用以维护合并。

继续考虑,合并需要端点的奇偶性相反才可行,因此需要维护左端点奇偶性 \(lodd\) 、右端点奇偶性 \(rodd\) 。

同时,考虑到 \(lmx,rmx\) 合并时会出现跨越两段的情况,需要再维护一个区间权值和 \(sum\) 。当左右可跨越时,可以用 \(lmx\) 与左子区间 \(sum\) 加 右子区间 \(lmx\) 取最大值, \(rmx\) 同理。需要注意, \(sum\) 不能用 \(lmx,rmx\) 替代,因为权值是有正有负的, \(sum\) 不一定是 \(lmx,rmx\) ,必须多维护一个 \(sum\) 。

对于 \(sum\) ,我们还需要来判断整个区间是否为有效区间,从而判断 \(sum\) 是否可用。为了少设一个变量保存区间是否整个有效(当然设了也行,写起来容易点),我们设 \(sum\) 初值为极小值 \(-10^{18}\) 的表示无效值,更新时取 \(sum\) 与左右子区间的 \(sum\) 的和的最大值即可。显然,左右子区间存在一个无效值,则区间的值一定无效。

因此,区间信息要维护 \(mx,lmx,rmx,lodd,rodd,sum\) 。

合并时, \(lodd,rodd\) 直接继承即可,接下来分两步:

  1. \(mx\) 取左右子区间 \(mx\) 的最大值, \(lmx,rmx\) 直接继承。

  2. 若左子区间 \(rodd\) 和右子区间 \(lodd\) 不同,则在第一步的基础上考虑跨越两段的情况。

    \(mx\) 需要再与左子区间 \(rmx\) 加右子区间 \(lmx\) 的和取最大值。

    \(lmx,rmx\) 考虑特殊情况,已经在考虑维护信息的时候分析过了。

    \(sum\) 也分析过了。

修改时,直接修改即可,过程非常朴素,就不讲了。

另外,由于线段树结构的问题,我需要多加一个表示区间是否存在的 \(exist\) 以用来合并无效区间时特判,这个完全可以用先判断后递归避免,但是我懒23333。

时间复杂度 \(O((n+m) \log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct T {
    bool exist = 0; // 区间是否存在
    ll mx = -1e18; // 有效区间最大值
    ll sum = -1e18; // 区间权值和(区间权值和不能用 lmx,rmx 替代)
    bool lodd = 0, rodd = 0; // 左/右端点的奇偶性
    ll lmx = -1e18, rmx = -1e18; // 从左/右端点出发的最大值
    friend T operator+(const T &a, const T &b) {
        if (!a.exist) return b;
        if (!b.exist) return a;
        T x = T();
        x.exist = 1;
        x.mx = max(a.mx, b.mx);
        x.lodd = a.lodd, x.rodd = b.rodd;
        x.lmx = a.lmx, x.rmx = b.rmx;
        if (a.rodd ^ b.lodd) {
            x.mx = max(x.mx, a.rmx + b.lmx);
            x.sum = max(x.sum, a.sum + b.sum); // 取最大值,防止溢出
            x.lmx = max(x.lmx, a.sum + b.lmx);
            x.rmx = max(x.rmx, a.rmx + b.sum);
        }
        return x;
    }
};
struct F {
    ll upd;
    T operator()(const T &x) {
        return{
            1,
            upd,
            upd,
            (bool)(upd % 2),(bool)(upd % 2),
            upd,upd,
        };
    }
};

template<class T, class F>
class SegmentTree {
    int n;
    vector<T> node;

    void update(int rt, int l, int r, int x, F f) {
        if (r < x || x < l) return;
        if (l == r) return node[rt] = f(node[rt]), void();
        int mid = l + r >> 1;
        update(rt << 1, l, mid, x, f);
        update(rt << 1 | 1, mid + 1, r, x, f);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

    T query(int rt, int l, int r, int x, int y) {
        if (r < x || y < l) return T();
        if (x <= l && r <= y) return node[rt];
        int mid = l + r >> 1;
        return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y);
    }

public:
    SegmentTree(const vector<T> &src) { init(src); }

    void init(const vector<T> &src) {
        assert(src.size() >= 2);
        n = src.size() - 1;
        node.assign(n << 2, T());
        function<void(int, int, int)> build = [&](int rt, int l, int r) {
            if (l == r) return node[rt] = src[l], void();
            int mid = l + r >> 1;
            build(rt << 1, l, mid);
            build(rt << 1 | 1, mid + 1, r);
            node[rt] = node[rt << 1] + node[rt << 1 | 1];
        };
        build(1, 1, n);
    }

    void update(int x, F f) { update(1, 1, n, x, f); }

    T query(int x, int y) { return query(1, 1, n, x, y); }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<T> a(n + 1);
    for (int i = 1;i <= n;i++) {
        int x;
        cin >> x;
        a[i] = {
            1,
            x,
            x,
            (bool)(x % 2),(bool)(x % 2),
            x,x,
        };
    }
    SegmentTree<T, F> sgt(a);
    while (m--) {
        int op;
        cin >> op;
        if (op == 0) {
            int l, r;
            cin >> l >> r;
            cout << sgt.query(l, r).mx << '\n';
        }
        else {
            int x, v;
            cin >> x >> v;
            sgt.update(x, { v });
        }
    }
    return 0;
}

标签:lmx,NC15162,int,询问,leq,rmx,区间,sum
From: https://www.cnblogs.com/BlankYang/p/17368436.html

相关文章

  • 离线询问
    -https://ac.nowcoder.com/acm/contest/54877/D观察题目,以猫猫的友善值为横坐标,与猫猫期望的友善值为纵坐标,则人类的友善值为纵坐标,期待的友善值为横坐标问题就转换为了求猫猫坐标左上角的最左上的人类坐标点对猫猫以坐标形式排个序,遍历每个猫猫,在遍历过程中维护最左上角的人......
  • 【洛谷】P2414 [NOI2011] 阿狸的打字机(AC自动机+离线询问)
    原题链接题意给定\(n\)个字符串,\(m\)次询问一个字符串\(x\)在另一个字符串\(y\)的出现次数。\(1\leqn,m\leq10^5\)。思路要解决多个字符串的问题,不难想到......
  • [20230308]12c以上版本模糊查询问题.txt
    [20230308]12c以上版本模糊查询问题.txt--//前几天看了链接http://www.itpub.net/thread-2148700-1-1.html,对方提到模糊查询慢的问题,实际上这个问题使用常规模式基本--//无......
  • L11_买东西询问是否有某个东西
    概述在日语中,买东西是想问店里有没有某个东西,可以采用:物品名称はありますか的句式。おまもりはありますか有护身符吗?动画会话A:このTシャツ見て......
  • L10_用日语询问某个东西多少钱
    概述动画会话A:たくさんありますね。有好多啊。B:すごいでしょう。これはサラサラヘア。これはツヤが出るティプ很棒吧。这款是让头发顺滑。这款是让头发出......
  • SQL SERVER 生僻字查询问题和关键字COLLATE
       先说问题,生僻字查询的问题,有的时候我们的数据里包含一些生僻字,在查询用Like模糊匹配的时候,发现有的查询不准确,测试数据如下:1--测试数据2ifnotobject_id(N'......
  • L9_用日语询问某个东西是什么
    动画会话A:ここが「デパ地か」だよ。这里就是百货商店的地下食品区。B:いろんな食べ物があって、いいよね。有各种吃的,真好。C:わあ、すごい。これは何なんですか。......
  • 【CCCC】L3-016 二叉搜索树的结构 (30分),,手动建堆(二叉搜索树节点询问),map写法
    problemL3-016二叉搜索树的结构(30分)二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树......
  • P6374 「StOI-1」树上询问
    P6374「StOI-1」树上询问Description给定一颗\(n\)个节点的树,有\(q\)次询问。每次询问给一个参数三元组\((a,b,c)\),求有多少个\(i\)满足这棵树在以\(i\)为......
  • AcWing1172. 祖孙询问
    题目描述给定一棵包含\(n\)个节点的有根无向树,节点编号互不相同,但不一定是\(1\simn\)。有\(m\)个询问,每个询问给出了一对节点的编号\(x\)和\(y\),询问\(x\)与......