BZOJ 4241: 历史研究 回滚莫队

title

BZOJ 4241

Description

IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
日记中记录了连续N天发生的时间,大约每天发生一件。
事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
JOI教授决定用如下的方法分析这些日记:

  1. 选择日记中连续的一些天作为分析的时间段

  2. 事件种类t的重要度为t*(这段时间内重要度为t的事件数)

  3. 计算出所有事件种类的重要度,输出其中的最大值

现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。

Input

第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1...XN,Xi表示第i天发生的事件的种类
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。

Output

输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度

Sample Input

5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4

Sample Output

9
8
8
16
16

HINT

1<=N<=10^5
1<=Q<=10^5
1<=Xi<=10^9 (1<=i<=N)

Source

JOI 2013~2014 春季training合宿 竞技1 By PoPoQQQ

analysis

蒟蒻选择回滚莫队。然而我觉得《全网最详细、最深的四类莫队算法讲解》里面的回滚莫队讲的挺好的,不想赘述了。

还是解释一下吧,回滚莫队把\(L\)指针放到\(R+1\),然后正常操作,其实就相当于:在运行时,我把\(1\sim L\)里的值删了,把\(1\sim R\)里的值又加回来,这样就相当于没有删掉任何值,所以其实就是用这样的思想去避免最大值被删掉的。

这是我第一个直接自己搞明白的莫队,\(happy!\)其他的三种莫队都是被大佬教会的。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
 
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
 
template<typename T>inline void write(T x)
{
    if (!x) { putchar('0'); return ; }
    if (x<0) putchar('-'), x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) putchar(ch[num--]);
}
 
struct Orz
{
    int l,r,id;
    ll ans;
}q[maxn];
int belong[maxn];
inline bool cmp1(Orz a,Orz b)
{
    return belong[a.l]^belong[b.l]?belong[a.l]<belong[b.l]:a.r<b.r;
}
 
inline bool cmp2(Orz a,Orz b)
{
    return a.id<b.id;
}
 
int cnt[maxn],b[maxn],a[maxn];
ll ans;
inline void add(int pos)
{
    ++cnt[b[pos]];
    ans=max(ans,1ll*cnt[b[pos]]*a[pos]);
}
 
inline void roll(int pos)
{
    --cnt[b[pos]];
}
 
inline ll query(int l,int r)
{
    int cnt2[maxn];
    ll res=0;
    for (int i=l; i<=r; ++i) cnt2[b[i]]=0;
    for (int i=l; i<=r; ++i) ++cnt2[b[i]],res=max(res,1ll*cnt2[b[i]]*a[i]);
    return res;
}
 
int n,m,block;
inline int solve(int qnum,int id)
{
    int L=min(n,block*id),l=L+1,r=l-1,i=qnum;
    for (int j=1; j<=n; ++j) cnt[j]=0;
    ans=0;
    for ( ; belong[q[i].l]==id; ++i)
    {
        if (belong[q[i].l]==belong[q[i].r])
        {
            q[i].ans=query(q[i].l,q[i].r);
            continue;
        }
        while (r<q[i].r) add(++r);
        ll tmp=ans;
        while (l>q[i].l) add(--l);
        q[i].ans=ans;
        while (l<L+1) roll(l++);
        ans=tmp;
    }
    return i;
}
 
int v[maxn];
int main()
{
    read(n);read(m);
    block=sqrt(n);
    for (int i=1; i<=n; ++i) read(a[i]),v[i]=a[i],belong[i]=(i-1)/block+1;
 
    sort(v+1,v+n+1);
    int newn=unique(v+1,v+n+1)-v-1;
    for (int i=1; i<=n; ++i) b[i]=lower_bound(v+1,v+newn+1,a[i])-v;
 
    for (int i=1; i<=m; ++i) read(q[i].l),read(q[i].r),q[i].id=i;
    sort(q+1,q+m+1,cmp1);
    int qnum=1;
    for (int i=1; i<=belong[n]; ++i) qnum=solve(qnum,i);
    sort(q+1,q+m+1,cmp2);
    for (int i=1; i<=m; ++i) write(q[i].ans),puts("");
    return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/11329993.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值