首页 > 其他分享 >Codeforces Round #852 (Div. 2)

Codeforces Round #852 (Div. 2)

时间:2023-02-13 14:12:32浏览次数:53  
标签:std info le return 852 int modify Codeforces Div

F. Rebrending

题目抽象为现有长度为 \(n\) 的数组 \(a_1,a_2,\cdots,a_n\),\(m\) 次询问,每次询问 \(\min\limits_{l\le i,j\le r,i\neq j} |a_i-a_j|\) \((1\le l< r\le n)\)。

此题和 CF765F 几乎一样,但是还是和原题有一些不一样的地方,询问次数更多,并且 \(a_i\le n\)。原题有一种做法是按 \(r\) 的大小排序将询问离线,用权值线段树维护区间对应权值最大值,\(a_i\) 的权值为 \(i\),再用树状数组或线段树维护区间两数绝对值差的最小值,原题 \(a_i\le 10^9\), 那么需要离散化或者动态开点,复杂度为 \(\mathcal{O}(n\log n\log 10^9+m\log n)\)。

那么我们还是考虑离线,因为 \(r\le n\),那么就不需要排序了,从左往右遍历所有元素,遍历到 \(a_i\) 时回答 \(r=i\) 的询问,那么我们只需要考虑 \(i-1\rightarrow i\) 对答案的影响。

\(a_j>a_i\) (\(l\le j\le r\)) 对答案的贡献为 \(a_j-a_i\)。

\(a_k<a_i\) (\(l\le k\le r\)) 对答案的贡献为 \(a_i-a_k\)。

先找到最大的 \(j\) 满足 \(a_j>a_i\),更新区间最小值,此时还可能存在 \(y\) 满足 \(a_y-a_i<a_j-a_i\),接着查询 \([a_i,\lfloor\frac{a_i+a_j}{2}\rfloor]\) 中最大的 \(y\) 满足 \(a_y>a_i\),一直重复查询直到不存在比 \(a_i\) 大的数,最多查询 \(\log i\) 次。

区间中比 \(a_i\) 小的数对答案的贡献和上述基本一样。

这里用树状数组维护区间两数绝对值差的最小值。

复杂度为 \(\mathcal{O}(n\log^{2}n)\)。

提交记录:
193417542

C++ Code
#include <bits/stdc++.h>

using i64 = long long;

template<class Info,
    class Merge = std::plus<Info>>
struct SegmentTree {
    const int n;
    const Merge merge;
    std::vector<Info> info;
    SegmentTree(int n) : n(n), merge(Merge()), info(4 << std::__lg(n)) {}
    SegmentTree(std::vector<Info> init) : SegmentTree(init.size()) {
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = merge(info[2 * p], info[2 * p + 1]);
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return merge(rangeQuery(2 * p, l, m, x, y), rangeQuery(2 * p + 1, m, r, x, y));
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
};

template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n = 0) {
        init(n);
    }
    
    void init(int n) {
        this->n = n;
        a.assign(n, T());
    }
    
    void add(int x, T v) {
        for (int i = x + 1; i <= n; i += i & -i) {
            a[i - 1] += v;
        }
    }
    
    T sum(int x) {
        auto ans = T();
        for (int i = x; i > 0; i -= i & -i) {
            ans += a[i - 1];
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {
        return sum(r) - sum(l);
    }
    
    int kth(T k) {
        int x = 0;
        for (int i = 1 << std::__lg(n); i; i /= 2) {
            if (x + i <= n && k >= a[x + i - 1]) {
                x += i;
                k -= a[x - 1];
            }
        }
        return x;
    }
};

struct Max {
    int x;
    Max(int x = -1) : x(x) {}
};

Max operator+(const Max &a, const Max &b) {
    return std::max(a.x, b.x);
}

constexpr int inf = 1E9;
struct Min {
    int x;
    Min(int x = inf) : x(x) {}
 
    Min &operator+=(Min a) {
        x = std::min(a.x, x);
        return *this;
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
        a[i]--;
    }

    std::vector<std::vector<std::pair<int, int>>> qry(n);
    for (int i = 0; i < m; i++) {
        int l, r;
        std::cin >> l >> r;

        l--, r--;
        qry[r].emplace_back(l, i);
    }

    SegmentTree<Max> seg(n);
    Fenwick<Min> fen(n);
    std::vector<int> ans(m);

    seg.modify(a[0], 0);
    for (int i = 1; i < n; i++) {
        int j = seg.rangeQuery(a[i], n).x;
        while (j != -1) {
            fen.add(n - 1 - j, a[j] - a[i]);
            j = seg.rangeQuery(a[i], (a[i] + a[j]) / 2 + 1).x;
        }

        int k = seg.rangeQuery(0, a[i] + 1).x;
        while (k != -1) {
            fen.add(n - 1 - k, a[i] - a[k]);
            k = seg.rangeQuery((a[i] + a[k] + 1) / 2, a[i] + 1).x;
        }

        seg.modify(a[i], i);
        
        for (auto &[l, j] : qry[i]) {
            ans[j] = fen.sum(n - l).x;
        }
    }

    for (int i = 0; i < m; i++) {
        std::cout << ans[i] << '\n';
    }

    return 0;
}

标签:std,info,le,return,852,int,modify,Codeforces,Div
From: https://www.cnblogs.com/kiddingma/p/17116134.html

相关文章

  • #0033. Educational Codeforces Round 3
    609A贪心优先选大的USBflashdrive609B先处理每个genre的书有多少本,然后直接枚举每次购买的是哪两种genre然后乘法原理即刻609C手下考虑balanced的长啥样。假设这n......
  • #0032. Educational Codeforces Round 2
    600A简单题但有个坑点在于会有空字符串600B一道可以用来实验upper_bound的题600C挺有趣的一道题。首先考虑怎样的字符串可以通过permutation变成palindrome:条件是至......
  • 自动生成div
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Docu......
  • Codeforces Round #852 (Div. 2)
    A.YetAnotherPromotion题意:买土豆,一种卖a元一公斤,买m公斤送一公斤;一种卖b元一公斤。求买n公斤土豆最少花多少钱。解:完全没有思考,把a*n,b*n,买尽可能多m倍数的土豆剩......
  • Codeforces Round #851 (Div. 2)-F. XOR, Tree, and Queries-树、异或、并查集
    题目:https://codeforces.com/contest/1788/problem/F题解:(首先他和线性基没什么瓜系)想这个问题大概可以分成几个部分:1、很自然地考虑记\(p_x\)表示从根节点走到x路径......
  • Codeforces Round #851 (Div. 2) D
    链接:https://codeforces.com/contest/1788/problem/D题意:数轴上有n个点,每个点会以相同的v向最近的点移动(若左右距离相等则向左),两点相遇则暂停,问最终数轴上剩下的点数即为......
  • Codeforces Round #547 (Div. 3) F2. Same Sum Blocks (贪心——最多不重叠区间数量
    题目https://codeforces.com/problemset/problem/1141/F2题意忽略;给出一个数组,求和相等的,不重叠子串的最大数量,并输出(题目有点绕)思路先求出数组前缀和,然后找出......
  • div、td 、p 等容器内强制换行和不换行的方法
    转载自:http://www.divcss5.com/html/h50327.shtml1、强制不换行,同时以省略号结尾。<divstyle="width:100px;overflow:hidden;white-space:nowrap;text-overflow:ellipsi......
  • Codeforces Round #851 (Div. 2) A-E
    比赛链接A题意给一串只包含\(1,2\)的数,找到最小的\(k\)使得\(\prod_{i=1}^ka_i=\prod_{i=k+1}^na_i\)。题解知识点:枚举。因为只有\(1,2\),所以考虑左右两......
  • Codeforces Round #541 (Div. 2) D - Gourmet choice 差分约束
    观察到n+m最多才2000个点,正解也不是差分约束但是它能跑:)建图比较平凡不记述难得的是用链式前向星T了,改vector过了  T9的话是加了随机化优化,cin读入,链式前向星存边......