BZOJ 4241 历史研究

Posted on 2017-03-07 10:52  ziliuziliu  阅读(128)  评论(0编辑  收藏  举报

就是区间众数的做法啦。。一模一样。

分块这种东西真的很容易写错。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 100050
using namespace std;
int n,q,x[maxn],hash[maxn],cnt=0,s[maxn],top=0,blo[maxn],tot=0,se[maxn],l,r;
int num[2050][2050],len,ll[maxn];
vector <int> v[maxn];
int read()
{
    int data=0;char ch;
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9')
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data;
}
void build()
{
    for (int i=1;i<=n;i++) hash[++cnt]=x[i];
    sort(hash+1,hash+cnt+1);cnt=unique(hash+1,hash+cnt+1)-hash-1;
    len=80;tot=1;
    for (int i=1;i<=n;i++)
    {
        x[i]=lower_bound(hash+1,hash+cnt+1,x[i])-hash;
        v[x[i]].push_back(i);
        blo[i]=tot;
        if ((i%len==0) || (i==n))
        {
            se[tot]=i;
            tot++;
        }
    }
    tot--;
    for (int i=1;i<=tot;i++)
    {
        long long mx=0;int ret;
        memset(ll,0,sizeof(ll));
        for (int j=se[i-1]+1;j<=n;j++)
        {
            ll[x[j]]++;
            if (mx<(long long)ll[x[j]]*hash[x[j]]) {mx=(long long)ll[x[j]]*hash[x[j]];ret=x[j];}
            if ((j%len==0) || (j==n)) num[i][blo[j]]=ret;
        }
    }
}
int ask(int x,int num)
{
    int l=0,r=v[num].size()-1,ans=-1,mid;
    while (l<=r)
    {
        mid=(l+r)>>1;
        if (v[num][mid]<=x) {ans=mid;l=mid+1;}
        else r=mid-1;
    }
    return ans+1;
}
long long work(int l,int r)
{
    top=0;
    if (blo[l]+1>=blo[r])
    {
        for (int i=l;i<=r;i++)
            s[++top]=x[i];
    }
    else
    {
        s[++top]=num[blo[l]+1][blo[r]-1];
        for (int i=l;i<=se[blo[l]];i++) s[++top]=x[i];
        for (int i=se[blo[r]-1]+1;i<=r;i++) s[++top]=x[i];
    }
    long long ret=0;
    for (int i=1;i<=top;i++)
        ret=max(ret,(long long)(ask(r,s[i])-ask(l-1,s[i]))*hash[s[i]]);
    return ret;
}
int main()
{
    n=read();q=read();
    for (int i=1;i<=n;i++) x[i]=read(); 
    build();
    for (int i=1;i<=q;i++)
    {
        l=read();r=read();
        printf("%lld\n",work(l,r));
    }
    return 0;
}