首页 > 其他分享 >NC208250 牛牛的最美味和最不美味的零食

NC208250 牛牛的最美味和最不美味的零食

时间:2023-05-02 17:11:32浏览次数:58  
标签:rt node NC208250 牛牛 int 区间 美味 零食

题目链接

题目

题目描述

牛牛为了减(吃)肥(好),希望对他的零食序列有更深刻的了解,所以他把他的零食排成一列,然后对每一个零食的美味程度都打了分,现在他有可能执行两种操作:

eat k:吃掉当前的第k个零食。右边的零食全部往左移动一位(编号减一)。

query i j:查询当前第i个零食到第j个零食里面美味度最高的和最低的零食的美味度。

输入描述

第一行包含两个数n, m,表示原始数组的元素个数和操作的个数。第二行包括n个数,表示原始数组。以下m行,每行格式为1 k或者2 i j,其中第一个数为1表示吃掉,为2表示询问。

输出描述

对每个询问操作输出一行,包括两个数,表示该范围内的最小值和最大值。

示例1

输入

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

输出

2 9
1 7

说明

\(1 \leq n, m \leq 10^6\) , \(1 \leq m \leq 10^6\) ,数组中的元素绝对值均不超过 \(10^9\)

题解

知识点:线段树,二分。

线段树本身不支持删除操作,我们考虑用区间有效点数代替删除的效果。

比较好的方法是用相对坐标表示查找的点,这样就可以利用线段树上二分来锁定我们要找的点或区间。

要删除当前第 \(k\) 个点,有两种情况:

  1. 若左子区间的有效点数大于等于 \(k\) ,那么要修改的点就在左子区间。
  2. 否则在右子区间。

要查询当前区间 \([l,r]\) 的值也是同理,有三种情况:

  1. 若左子区间的有效点大于等于 \(r\) ,则查询左子区间。
  2. 否则若左子区间的有效点小于 \(l\) ,则查询右子区间。
  3. 否则可以确定查询区间跨越了左右子区间,则两边都要查询。

这道题展示了线段树上二分查找点、区间的基本写法,是个值得一做的好题。

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

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

代码

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

struct T {
    int sum;
    int mi;
    int mx;
    static T e() { return { 0,(int)2e9,(int)-2e9 }; }
    friend T operator+(const T &a, const T &b) {
        return {
            a.sum + b.sum,
            min(a.mi, b.mi),
            max(a.mx,b.mx)
        };
    }
};
class SegmentTree {
    int n;
    vector<T> node;

    void update(int rt, int l, int r, int x) {
        if (l == r) return node[rt] = { 0,(int)2e9,(int)-2e9 }, void();
        int mid = l + r >> 1;
        if (node[rt << 1].sum >= x)update(rt << 1, l, mid, x);
        else update(rt << 1 | 1, mid + 1, r, x - node[rt << 1].sum);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

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

public:
    SegmentTree(int _n = 0) { init(_n); }
    SegmentTree(int _n, const vector<T> &src) { init(_n, src); }

    void init(int _n) {
        n = _n;
        node.assign(n << 2, T::e());
    }
    void init(int _n, const vector<T> &src) {
        init(_n);
        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) { update(1, 1, n, x); }

    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 };
    }
    SegmentTree sgt(n, a);
    while (m--) {
        int op;
        cin >> op;
        if (op == 1) {
            int k;
            cin >> k;
            sgt.update(k);
        }
        else {
            int i, j;
            cin >> i >> j;
            auto [sum, mi, mx] = sgt.query(i, j);
            cout << mi << ' ' << mx << '\n';
        }
    }
    return 0;
}

标签:rt,node,NC208250,牛牛,int,区间,美味,零食
From: https://www.cnblogs.com/BlankYang/p/17367930.html

相关文章

  • 糖果美味值 (动态规划)
    描述:有n天,每天有一种糖果,糖果具有一定美味值;规定小美今天吃了明天就不能吃,但有k次机会打破规则。求这n天小美能吃到的最大美味值。第一行输入n,k;第二行输入n天中每天的糖果的美味值。输出最大美味值。样例输入:711234567输出:19importjava.util.Scanner;/**......
  • BC7-牛牛的字符矩形
    题目描述牛牛尝试用键盘读入一个字符,然后在屏幕上显示用这个字符组成的3*3的矩形。输入描述一行读入一个char类型的字符。输出描述输出这个字符组成的3*3矩形。......
  • BC6-牛牛的第二个整数
    题目描述牛牛从键盘上输入三个整数,并尝试在屏幕上显示第二个整数。输入描述一行输入3个整数,用空格隔开。输出描述请输出第二个整数的值。示例1输入:123输出:2......
  • BC5-牛牛学说话之-字符
    题目描述会说浮点数之后,牛牛开始尝试字符。输入一个字符,输出这个字符。输入描述输入一个字符,范围在ascii范围内输出描述输出这个字符示例1输入:a输出:a解题思路......
  • BC4-牛牛学说话之-浮点数
    题目描述会说整数之后,牛牛开始尝试浮点数(小数),输入一个浮点数,输出这个浮点数。输入描述输入一个浮点数输出描述输出一个浮点数,保留三位小数示例1输入:1.359578输......
  • BC3-牛牛学说话之-整数
    题目描述牛牛刚刚出生,嗷嗷待哺,一开始他只能学说简单的数字,你跟他说一个整数,他立刻就能学会。输入一个整数,输出这个整数。输入描述输入一个整数,范围在32位有符号整数范围......
  • 牛客小白月赛65——D-牛牛取石子
    链接:https://ac.nowcoder.com/acm/contest/49888/D来源:牛客网牛牛和牛妹在玩游戏,他们的游戏规则是这样的:一共有两堆石子,第一堆有aaa个,第二堆有bbb个,牛牛和牛妹轮流取......
  • 牛客小白月赛65D题 牛牛取石头 题解
    原题链接第一眼看到这道题,其实很容易会联想到经典的bashgame问题这道题并没有巴什博弈那么复杂,但也算一道比较新颖的博弈论题吧还是很适合作为一道博弈论入门题的题......
  • 牛客小白月赛65 D-牛牛取石子(博弈论)
    https://ac.nowcoder.com/acm/contest/49888/D题目大意:一共有两堆石子,第一堆a个,第二堆b个,牛牛(先手)和牛妹轮流取石子:2种方案种挑一种1.第一堆取1个,第二堆取2个2......
  • 牛牛的构造(构造)
    题目链接题目描述:请你给出一个长度为\(n\)的数组\(a\),数组\(a\)中的数是\(1\)到\(n\)的排列,即其中每个数的范围都是\([1,n]\),且每个数各不相同。同时使得这......