zoukankan      html  css  js  c++  java
  • [回滚莫队] AtCoder 歴史の研究

    题目大意

    给定长为 (n(1leq nleq 10^5)) 的序列 ({a_n}),其中 (1leq a_ileq 10^9)

    (q(1leq qleq 10^5)) 个询问,每次询问序列的一个区间 ([L,R]) 内的一个数乘以它在这个区间内出现的次数的最大值。

    题解

    发现询问可以离线,如果用普通莫队来做,可以发现加点很容易,每加入一个数,更新一下 (mathrm{maxval}) 即可。但是删点很困难,因为之前的 (mathrm{maxval}) 被覆盖了,难以回退。此时就可以使用回滚莫队来做。

    将整个序列按根号大小分块,将所有询问按左端点所属块为第一关键字升序排序,按右端点为第二关键字升序排序。每次我们对所有左端点所属块相同的询问一起处理,这样询问右端点一定是单调递增的。现在考察这样的一组询问:

    设当前组询问的左端点全部在块 (x) 内,则设 (L=mathrm{Right}(x)+1,R=mathrm{Right}(x))

    若询问的左右端点同属同一块中,则暴力处理该询问,单次 (O(sqrt n))

    否则,由于同一组内询问的右端点单调递增,我们先把 (R) 不断移到当前询问的右端点,最多移动 (O(n)) 次。但此时左端点可能是无序的,我们先记录下原先的 (mathrm{maxval}),然后把 (L) 移动到询问的位置,记录此询问的答案,然后将 (L) 回滚到 (mathrm{Right}(x)+1),恢复到上一次的 (mathrm{maxval}),由于 (L) 是在块内移动,此处 (L) 移动的是 (O(sqrt n)) 的。

    暴力计算块内询问和移动 (L) 对时间复杂度的贡献是 (qsqrt n)。由于所有询问最多分为 (sqrt n) 组,因此移动 (R) 对时间复杂度带来的贡献是 (O(nsqrt n))。因此回滚莫队的时间复杂度为 (O((n+q)sqrt n))

    此题注意还要进行离散化。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define LL long long
    
    template<typename elemType>
    inline void Read(elemType& T) {
        elemType X = 0, w = 0; char ch = 0;
        while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        T = (w ? -X : X);
    }
    
    int BLOCK_SIZE, BLOCK_NUM;
    int a[100010], cnt[100010], belong[100010], id[100010], pos[100010];
    LL ans[100010];
    pair<int, int> ask[100010];
    int N, Q, L, R;
    LL mxval;
    
    vector<int> HashData;
    
    void Discretization() {
        HashData.push_back(-(1 << 30));
        for (int i = 1; i <= N; ++i)
            HashData.push_back(a[i]);
        sort(HashData.begin(), HashData.end());
        HashData.erase(unique(HashData.begin(), HashData.end()), HashData.end());
        for (int i = 1; i <= N; ++i)
            pos[i] = lower_bound(HashData.begin(), HashData.end(), a[i]) - HashData.begin();
    }
    
    bool cmp(int a, int b) {
        if (belong[ask[a].first] == belong[ask[b].first])
            return ask[a].second < ask[b].second;
        return belong[ask[a].first] < belong[ask[b].first];
    }
    
    void BuildBlock() {
        BLOCK_SIZE = sqrt(N);
        BLOCK_NUM = (N - 1) / BLOCK_SIZE + 1;
        for (int i = 1; i <= BLOCK_NUM; ++i)
            for (int j = (i - 1) * BLOCK_SIZE + 1; j <= min(N, i * BLOCK_SIZE); ++j)
                belong[j] = i;
    }
    
    void Add(int x) { mxval = max(mxval, 1LL * a[x] * (++cnt[pos[x]])); }
    void Clear() { for (int i = L; i <= R; ++i) cnt[pos[i]] = 0; }
    LL Violent(int l, int r) {
        LL res = 0;
        for (int i = l; i <= r; ++i) ++cnt[pos[i]];
        for (int i = l; i <= r; ++i) {
            if (cnt[pos[i]]) {
                res = max(res, 1LL * a[i] * cnt[pos[i]]);
                cnt[pos[i]] = 0;
            }
        }
        return res;
    }
    
    int main() {
        Read(N); Read(Q);
        BuildBlock();
        for (int i = 1; i <= N; ++i)
            Read(a[i]);
        Discretization();
        for (int i = 1; i <= Q; ++i) {
            id[i] = i;
            Read(ask[i].first);
            Read(ask[i].second);
        }
        sort(id + 1, id + Q + 1, cmp);
        for (int i = 1; i <= Q; ++i) {
            int l = ask[id[i]].first, r = ask[id[i]].second;
            if (belong[l] != belong[ask[id[i - 1]].first]) {
                Clear();
                R = belong[l] * BLOCK_SIZE; L = R + 1; mxval = 0;
            }
            if (belong[l] == belong[r])
                ans[id[i]] = Violent(l, r);
            else {
                while (R < r) Add(++R);
                LL temp = mxval;
                for (int j = L - 1; j >= l; --j)
                    mxval = max(mxval, 1LL * a[j] * (++cnt[pos[j]]));
                ans[id[i]] = mxval;
                mxval = temp;
                for (int j = L - 1; j >= l; --j)
                    --cnt[pos[j]];
            }
        }
        for (int i = 1; i <= Q; ++i)
            printf("%lld
    ", ans[i]);
    
        return 0;
    }
    
  • 相关阅读:
    Windows10系统中实现Android的SDK和Android studio的配置
    神经网络框架-Pytorch使用介绍
    在各个平台系统中安装Pytorch
    Jetbrain的破解
    python的collections模块的学习
    python自带的用于解析HTML的库HtmlParser
    python利用urllib和urllib2抓取百度贴吧的页面程序并下载下来在本地
    Windows下多个版本的python的使用(粘贴其他人的博客只用于自己学习,如有侵权直接删帖)
    线程同步的几种方法
    事务隔离级别
  • 原文地址:https://www.cnblogs.com/AEMShana/p/14767849.html
Copyright © 2011-2022 走看看