bzoj 4241: 历史研究

传送门

传说中的回滚莫队。

按左端点所在块为第一关键字,右端点位置为第2关键字排序。

分别把左端点在同一个块中的询问一起处理,从这个块的下一个块的第一个元素开始加,因为右端点单调递增,只有加元素的操作。

然后对于左边的部分,对每个询问暴力加左边的然后考虑答案就好了。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=1e5+7;
typedef long long LL;
using namespace std;
int n,m,col[N],ls[N],bl[N],kk,sz;
LL ans[N];

template<typename T> void read(T &x) {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

struct node {
    int id,l,r;
    friend bool operator <(const node &A,const node &B) {
        return bl[A.l]<bl[B.l]||(bl[A.l]==bl[B.l]&&A.r<B.r);
    }
}qs[N];

int cnt[N],lz[N];
LL ansnow=-1;
void add(int x,int id) {
    if(lz[x]!=id) lz[x]=id,cnt[x]=1;
    else cnt[x]++;
    ansnow=max(ansnow,(LL)cnt[x]*ls[x]);
}

int tpc[N],vis[N],tot;
LL tpadd(int l,int r,int id) {
    tot++;
    LL tpans=ansnow;
    for(int i=l;i<=r;i++) {
        int x=col[i];
        if(vis[x]!=tot) vis[x]=tot,tpc[x]=1;
        else tpc[x]++;
        int y=(lz[x]==id?cnt[x]:0);
        tpans=max(tpans,(LL)(tpc[x]+y)*ls[x]);
    }
    return tpans;
}

void solve() {
    int nl,nr;
    for(int i=1;i<=m;i++) {
        if(i==1||bl[qs[i].l]!=bl[qs[i-1].l]) //if(bl[qs[i].l]!=bl[qs[i-1].l])
            nl=nr=(bl[qs[i].l]+1)*kk,ansnow=-1;
        while(nr<qs[i].r) add(col[++nr],bl[qs[i].l]);
        ans[qs[i].id]=tpadd(qs[i].l,min(nl,qs[i].r),bl[qs[i].l]);
    }
} 

int main() {
    read(n); read(m);
    kk=sqrt(n); kk=max(kk,1);
     for(int i=1;i<=n;i++) {
        read(col[i]); 
        ls[i]=col[i];
        bl[i]=(i-1)/kk;
    }
    sort(ls+1,ls+n+1);
    sz=unique(ls+1,ls+n+1)-(ls+1);
    for(int i=1;i<=n;i++) 
        col[i]=lower_bound(ls+1,ls+sz+1,col[i])-ls;
    for(int i=1;i<=m;i++) {
        read(qs[i].l);
        read(qs[i].r);
        qs[i].id=i;
    }
    sort(qs+1,qs+m+1);
    solve();
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
    return 0;
}
/*
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
*/
View Code

 

posted @ 2018-01-31 08:14  啊宸  阅读(181)  评论(0编辑  收藏  举报