Bzoj4241: 历史研究——回滚莫队

题面

  Bzoj

解析

  今天Doggu讲了根号类算法,这道题使用的就是其中之一的回滚莫队。

  这道题显然支持离线操作,询问区间,立即联想到莫队,对于区间扩大的信息更新是很容易的,但要区间缩小,信息的更新就很难了,于是就有一个叫做回滚莫队的东西。思路大体与莫队一致,只是对于块内询问每一次都暴力解决, 对于跨越块的询问,固定左指针在块的右端点+1的位置,先延伸右指针, 记录此时的答案now, 再延伸左指针,统计答案,然后左指针撤回到所在块的右端点+1的位置,同时将之前记录的答案now赋给现在的答案,这个操作叫做回滚。

  还有要注意常数优化,我之前的写法写挂了无数次。

 代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;

template<class T>
inline void read(T &re)
{
    re=0;
    T sign=1;
    char tmp;
    while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;
    re=tmp-'0';
    while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');
    re*=sign;
}

int n, Q, siz, pos[maxn], a[maxn], b[maxn], tot, t[maxn];
ll ans[maxn];

struct question{
    int l, r, num;
}q[maxn];

inline bool cmp(question x, question y)
{
    if(pos[x.l] == pos[y.l])
        return x.r < y.r;
    return pos[x.l] < pos[y.l];
}

inline void work()
{
    register int las = 0, L, R;
    register ll res = 0;
    for(register int i = 1; i <= Q; ++i)
    {
        if(pos[q[i].l] != las)
        {
            for(register int j = 1; j <= tot; ++j)
                t[j] = 0;
            res = 0;
            L = min(siz * pos[q[i].l], n) + 1;
            R = L - 1;
        }
        if(pos[q[i].l] == pos[q[i].r])
        {
            for(register int j = q[i].l; j <= q[i].r; ++j)
            {
                t[a[j]] ++;
                res = max(res, 1LL * b[a[j]] * t[a[j]]);
            }
            for(int j = q[i].l; j <= q[i].r; ++j)
                t[a[j]] --;
            ans[q[i].num] = res;
            res = 0;
            las = pos[q[i].l];
        }
        else
        {
            while(R < q[i].r)    
            {
                R++;
                t[a[R]]++;
                res = max(res, 1LL * b[a[R]] * t[a[R]]);
            }
            ll now = res;
            register int ql = L;
            while(q[i].l < L)
            {
                L --;
                t[a[L]] ++;
                res = max(res, 1LL * b[a[L]] * t[a[L]]);
            }
            ans[q[i].num] = res;
            while(L < ql)
                t[a[L++]] --;
            res = now;
            las = pos[q[i].l];
        }
    }
}

int main()
{
    read(n);read(Q);
    siz = (int)sqrt(n * 1.0 + 0.5);
    for(register int i = 1; i <= n; ++i)
        read(a[i]), b[i] = a[i];
    sort(b + 1, b + n + 1);
    tot = unique(b + 1, b + n + 1) - b - 1;
    for(register int i = 1; i <= n; ++i)
    {
        a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
        pos[i] = (i - 1) / siz + 1;
    }
    for(register int i = 1; i <= Q; ++i)
    {
        read(q[i].l);read(q[i].r);
        q[i].num = i;
    }
    sort(q + 1, q + Q + 1, cmp);
    work();
    for(int i = 1 ; i <= Q; ++i)
        printf("%lld
", ans[i]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Joker-Yza/p/11234200.html