【问题标题】:CSES Range Query Question: Salary QueriesCSES范围查询问题:薪资查询
【发布时间】:2020-08-17 18:09:23
【问题描述】:

我正在尝试解决这个问题:https://cses.fi/problemset/task/1144/

给定一个最多包含 200000 元素的数组,我的任务是处理最多 200000 的查询,这些查询要么要求我更新数组中的单个值,要么要求我查找 a​​ 和b 位于给定范围内(例如,查询会询问从索引15 有多少元素在[2, 3] 范围内)。

我目前的想法是首先对给定数组中的值使用索引压缩(因为值可以高达10^9,所以保持一个简单的出现数组会超出存储限制),然后保留另一个数组,其中包含每个压缩数字的出现次数。然后,可以使用求和段树来处理和更新查询。

但是,我在尝试实施这种方法时遇到了问题。我意识到更新单个数组值会迫使我更改压缩数组。

例如,给定一个数组[1, 5, 3, 3, 2],我将定义一个压缩函数C,这样

C[1] = 0;
C[2] = 1;
C[3] = 2;
C[5] = 3;

然后,出现数组将是[1, 1, 2, 1],并且处理求和查询将是高效的。但是,如果我被指示更新一个值,例如,将第三个元素更改为4,那么一切都会失去平衡。压缩函数必须更改为

C[1] = 0;
C[2] = 1;
C[3] = 2;
C[4] = 3;
C[5] = 4;

这将迫使我重建我的出现数组,从而导致O(N) 更新时间。

由于N 可以达到200000,因此我目前的方法无法有效地解决问题,尽管我认为我对索引压缩有正确的想法。有人可以用我的方法指出正确的方向吗?

【问题讨论】:

    标签: algorithm data-structures segment-tree range-query


    【解决方案1】:

    您在使用索引压缩方面有正确的想法 - 好主意!由于N 最多只能达到200000,因此保留一个出现数组最多需要200000 元素作为给定数组的初始值,而不是10^9 数组索引。

    据你自己说,你面临的问题是在处理查询过程中遇到新值时。你是对的;这会使发生数组失去平衡并导致更新必须在O(N) 时间运行。这个问题的解决方案只是对您当前的方法进行微小的修改。

    要解决遇到新值的问题,我们可以确保我们永远不会遇到任何新值。我们可以通过在构造总和段树之前读入所有查询来做到这一点。这将导致最大N + 2*Q 唯一值,或在最坏的情况下600000,这足以构造一个具有问题的 512MB 存储限制的发生数组。之后,总和段树将能够有效地回答这些查询。

    所以最终解决这个问题的一个策略是输入每个唯一的数字,然后构造一个索引压缩函数,然后使用求和段树来有效地处理求和查询。

    在未来,请记住,在这些类型的查询回答问题中,在预计算之前读入所有输入可能会很有用。祝你的程序好运。

    【讨论】:

      【解决方案2】:

      首先,考虑幼稚:对于每次更新,更新数组。对于每个查询,扫描整个数组并收集您的答案。该解决方案的复杂性在于O(n) 更新、O(n) 查询。不好。

      我们可以想出一个时间复杂度可能更差的不同解决方案,但它可以提示我们最终的结果是什么。始终维护源数组,但也要保留 value->frequency 的哈希图。然后,当您更新时,以旧值减少频率并以新值增加频率。现在,对于查询,遍历该查询范围的所有值并将它们相加以获得您的答案。这会导致O(1) 更新和O(r-l) 查询,因此我们有很好的更新但查询很糟糕。但是,如果我们可以只是加快这些查询的速度,这个结果可以得到改善!输入细分树

      传统上,您会在创建时一直构建一个分段树,直到它的叶子。然而,我们名义上想要一个范围从0-10^9 的段树,所以我们绝对不可能生成那么多内存(这样做会超时)。然而,如果我们创建一个段树,但对于每个节点,如果它们从未被使用过,它的子节点是隐式的。也就是说,如果子节点中没有元素,则不要创建子节点。这个结构被恰当地命名为隐式段树。这里的想法是像往常一样实现你的段树,除了跳过构造函数中初始化左右孩子的部分。现在,当您由于部分范围查询而需要深入研究您的孩子时,请检查它们是否存在,如果不存在,请创建它们。否则,由于您从未需要制作它们,因此假设这些节点中的值之和为 0!

      最终解决方案如下:创建一个可查询最大值的段树(如果您不必交互式回答,请考虑保存并扫描您的查询以找到最大 r 值,但您没有到)。 注意使它成为隐式段树。每次更新后维护源数组,并在你的树上做点更新,这将是O(log(max value))。查询是常规的段树范围查询,因此它们将是O(log(max value))。它就在那里!

      【讨论】:

        【解决方案3】:

        您可以使用基于策略的数据结构,它有一些有用的方法,例如 order_of_key() - 返回小于给定 num 的项目数。我们可以像 getcnt(b+1) 一样调用它两次 - getcnt(a) - 它给出给定范围之间的项目数。有关这方面的更多信息 - 您可以参考 - https://codeforces.com/blog/entry/11080https://gcc.gnu.org/onlinedocs/libstdc++/manual/policy_data_structures.html

        经过大量研究,我发现这个 STL 在使用基于树的结构时非常有用。

        我测试了下面的代码,它通过了所有的测试用例。

        #include<bits/stdc++.h>
        #include <ext/pb_ds/assoc_container.hpp> // Common file
        #include <ext/pb_ds/tree_policy.hpp> // Including tree_order_statistics_node_update
         
        using namespace std;
        using namespace __gnu_pbds;
         
        template<class T> using cust_set = tree<
        T,
        null_type,
        less<T>,
        rb_tree_tag,
        tree_order_statistics_node_update>;
        cust_set<array<int,2>> freq;
         
        int getcnt(int x)
        {
            return freq.order_of_key({x,0});
        }
        int main()
        {
            int n,q;
            scanf("%d%d",&n,&q);
            vector<int> emp(n);
            
            int sal;
            for(int i=0;i<n;i++)
            {
                cin >> emp[i];
                freq.insert({emp[i],i});
            }
            char c;
            int x,a,b;
            while(q--)
            {
                cin>> c;
                int ans=0;
                if(c=='?')
                {
                    cin>>a>>b;
                    cout << getcnt(b+1) - getcnt(a)<<"\n";
                }
                else
                {
                    cin>>a>>b;
                    --a;
                    freq.erase({emp[a],a});
                    emp[a] = b;
                    freq.insert({emp[a],a});
                }
            }
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 2022-11-04
          • 2012-04-13
          • 1970-01-01
          • 2021-10-28
          • 2019-07-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多