【BZOJ4241】历史研究(回滚莫队)

题目:

BZOJ4241

分析:

本校某些julao乱膜的时候发明了个“回滚邹队”,大概意思就是某个姓邹的太菜了进不了省队回滚去文化课

回滚莫队裸题qwq(话说这个名字是不是莫队本人起的啊这么萌zui

首先看到题询问区间信息+没强制在线,妥妥的莫队。然而朴素的莫队(开个桶记每种事件当前的重要度,用set或者堆之类维护一下答案)要\(O(n\sqrt n \log n)\),直接T了……

兔崽子给我说有一种神奇的分块做法,然而我太菜了还没写,先挖个坑以后再补。

然后我去网上orz题解,看到一种叫“回滚莫队”的神奇的东西。可以发现,朴素莫队的问题在于区间变长的时候可以\(O(1)\)更新答案,但是为了维护区间变短必须要套个\(\log n\)的数据结构。所以,如果不存在区间变短的情况,就可以直接\(O(1)\)更新答案,总复杂度\(O(n\sqrt n)\)了。

考虑左端点在同一块中的所有询问,它们的右端点是单调非降的。对于左右端点在同一块中的询问,直接暴力查询即可。否则,设左端点所在块的下一块开头为\(pos\),用一个指针\(r\)往右扫,统计\([pos,r]\)的答案。此时还有\([l,pos)\)的答案没有统计。对于每个询问,暴力\(O(\sqrt n)\)统计这部分答案,最后对两部分答案取\(max\)即可。具体参见代码。

代码:

朴素莫队(TLE):

(一开始离散化写炸了WA了几发……菜死了)

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <cmath>
#define _ 0
using namespace std;

namespace zyt
{
    template<typename T>
    inline bool read(T &x)
    {
        char c;
        bool f = false;
        x = 0;
        do
            c = getchar();
        while (c != EOF && c != '-' && !isdigit(c));
        if (c == EOF)
            return false;
        if (c == '-')
            f = true, c = getchar();
        do
            x = x * 10 + c - '0', c = getchar();
        while (isdigit(c));
        if (f)
            x = -x;
        return true;
    }
    template<typename T>
    inline void write(T x)
    {
        char buf[20];
        char *pos = buf;
        if (x < 0)
            putchar('-'), x = -x;
        do
            *pos++ = x % 10 + '0';
        while (x /= 10);
        while (pos > buf)
            putchar(*--pos);    
    }
    typedef long long ll;
    const int N = 1e5 + 10, Q = 1e5 + 10;
    int n, q, block, belong[N], arr[N], tmp[N];
    ll ans[N];
    struct _ask
    {
        int l, r, id;
        bool operator < (const _ask &b) const
        {
            return belong[l] == belong[b.l] ? r < b.r : belong[l] < belong[b.l];
        }
    }ask[Q];
    namespace Mo_Algorithm
    {
        priority_queue<ll> pq, del;
        ll num[N];
        void update(const int pos, const int x)
        {
            del.push(num[pos]);
            num[pos] += (ll)tmp[pos] * x;
            pq.push(num[pos]);
            while (!del.empty() && pq.top() == del.top())
                pq.pop(), del.pop();
        }
        void solve(const int maxx)
        {
            int l = 1, r = 1;
            for (int i = 1; i <= maxx; i++)
                pq.push(0);
            update(arr[1], 1);
            for (int i = 1; i <= q; i++)
            {
                while (l < ask[i].l)
                    update(arr[l++], -1);
                while (l > ask[i].l)
                    update(arr[--l], 1);
                while (r < ask[i].r)
                    update(arr[++r], 1);
                while (r > ask[i].r)
                    update(arr[r--], -1);
                ans[ask[i].id] = pq.top();
            }
        }
    }
    int work()
    {
        read(n), read(q);
        block = pow(n, 0.5);
        for (int i = 1; i <= n; i++)
        {
            read(arr[i]), tmp[i] = arr[i];
            belong[i] = (i - 1) / block + 1;
        }
        sort(tmp + 1, tmp + n + 1);
        int cnt = unique(tmp + 1, tmp + n + 1) - tmp;
        for (int i = 1; i <= n; i++)
            arr[i] = lower_bound(tmp + 1, tmp + cnt, arr[i]) - tmp;
        for (int i = 1; i <= q; i++)
        {
            read(ask[i].l), read(ask[i].r);
            ask[i].id = i;
        }
        sort(ask + 1, ask + q + 1);
        Mo_Algorithm::solve(cnt);
        for (int i = 1; i <= q; i++)
            write(ans[i]), putchar('\n');
        return (0^_^0);
    }
}
int main()
{
    return zyt::work(); 
}

回滚莫队(AC):

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <cmath>
#define _ 0
using namespace std;

namespace zyt
{
    template<typename T>
    inline bool read(T &x)
    {
        char c;
        bool f = false;
        x = 0;
        do
            c = getchar();
        while (c != EOF && c != '-' && !isdigit(c));
        if (c == EOF)
            return false;
        if (c == '-')
            f = true, c = getchar();
        do
            x = x * 10 + c - '0', c = getchar();
        while (isdigit(c));
        if (f)
            x = -x;
        return true;
    }
    template<typename T>
    inline void write(T x)
    {
        char buf[20];
        char *pos = buf;
        if (x < 0)
            putchar('-'), x = -x;
        do
            *pos++ = x % 10 + '0';
        while (x /= 10);
        while (pos > buf)
            putchar(*--pos);    
    }
    typedef long long ll;
    const int N = 1e5 + 10, Q = 1e5 + 10;
    int n, q, block, belong[N], arr[N], tmp[N];
    ll ans[N];
    struct _ask
    {
        int l, r, id;
        bool operator < (const _ask &b) const
        {
            return belong[l] == belong[b.l] ? r < b.r : belong[l] < belong[b.l];
        }
    }ask[Q];
    inline int begin(const int a)
    {
        return (a - 1) * block + 1;
    }
    namespace Mo_Algorithm
    {
        ll solve_small(const int l, const int r)
        {
            static ll num[N];
            ll ans = 0;
            for (int i = l; i <= r; i++)
                ans = max(ans, num[arr[i]] += tmp[arr[i]]);
            for (int i = l; i <= r; i++)
                num[arr[i]] = 0;
            return ans;
        }
        void solve(const int maxx)
        {
            static ll num[N];
            ll now = 0;
            int l, r, lbegin;
            for (int i = 1; i <= q; i++)
            {
                if (belong[ask[i].l] != belong[ask[i - 1].l])
                {
                    memset(num, 0, sizeof(ll[maxx + 1]));
                    lbegin = begin(belong[ask[i].l] + 1), l = lbegin, r = lbegin - 1;
                    now = 0;
                }
                if (belong[ask[i].l] == belong[ask[i].r])
                    ans[ask[i].id] = solve_small(ask[i].l, ask[i].r);
                else
                {
                    while (r < ask[i].r)
                    {
                        ++r;
                        now = max(now, num[arr[r]] += tmp[arr[r]]);
                    }
                    ll bck = now;
                    while (l > ask[i].l)
                    {
                        --l;
                        now = max(now, num[arr[l]] += tmp[arr[l]]);
                    }
                    ans[ask[i].id] = now;
                    while (l < lbegin)
                    {
                        num[arr[l]] -= tmp[arr[l]];
                        ++l;
                    }
                    now = bck;
                }
            }
        }
    }
    int work()
    {
        read(n), read(q);
        block = pow(n, 0.5);
        for (int i = 1; i <= n; i++)
        {
            read(arr[i]), tmp[i] = arr[i];
            belong[i] = (i - 1) / block + 1;
        }
        sort(tmp + 1, tmp + n + 1);
        int cnt = unique(tmp + 1, tmp + n + 1) - tmp;
        for (int i = 1; i <= n; i++)
            arr[i] = lower_bound(tmp + 1, tmp + cnt, arr[i]) - tmp;
        for (int i = 1; i <= q; i++)
        {
            read(ask[i].l), read(ask[i].r);
            ask[i].id = i;
        }
        sort(ask + 1, ask + q + 1);
        Mo_Algorithm::solve(cnt);
        for (int i = 1; i <= q; i++)
            write(ans[i]), putchar('\n');
        return (0^_^0);
    }
}
int main()
{
    return zyt::work(); 
}

猜你喜欢

转载自www.cnblogs.com/zyt1253679098/p/10159279.html