[莫队][离散化]luogu P3709 大爷的字符串题

https://www.luogu.org/problem/P3709

分析

从题目描述可以看出来出题人语文不行

理清题目描述后,其实是问在一个区间内取出一个严格上升数列,取完区间需要多少次

这个再思考一下,其实就是在问出现最多的数出现了多少次

由于值域1e9,我们考虑离散

由于可以离线的不带修区间操作,我们考虑莫队

离散后,times数组记录某数字出现了多少次,num数组记录有多少数字出现了i次

至于为什么涉及到答案时是O(1)的,因为当前答案失效后,它也只减少了一次出现次数啊,所以是原答案-1

 

#include <iostream> 
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=2e5+10;
struct Query {
    int l,r,id;
}t[N];
int n,fn,m,fm;
int a[N],b[N],times[N],num[N],id[N],ans[N],lans;

bool CMP(Query a,Query b) {
    return id[a.l]<id[b.l]||id[a.l]==id[b.l]&&(((id[a.l]&1)^1)^(a.r<b.r));
}

void Solve(int x,bool type) {
    if (type) {
        num[times[x]]--;
        times[x]++;num[times[x]]++;
        lans=max(lans,times[x]);
    }
    else {
        num[times[x]]--;if (lans==times[x]&&num[times[x]]==0) lans--;
        times[x]--;num[times[x]]++;
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);fn=unique(b+1,b+n+1)-b-1;
    for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+fn+1,a[i])-b;
    for (int i=1;i<=m;i++) scanf("%d%d",&t[i].l,&t[i].r),t[i].id=i;
    fm=sqrt(m);
    for (int i=1;i<=m;i++) id[i]=i/fm+(i%fm>0);
    sort(t+1,t+m+1,CMP);
    num[0]=n;
    int l=1,r=1;Solve(a[1],1);
    for (int i=1;i<=m;i++) {
        while (r<t[i].r) Solve(a[++r],1);while (t[i].l<l) Solve(a[--l],1);
        while (l<t[i].l) Solve(a[l++],0);while (t[i].r<r) Solve(a[r--],0);
        ans[t[i].id]=lans;
    }
    for (int i=1;i<=m;i++) printf("%d\n",-ans[i]);
}
View Code

 

posted @ 2019-08-20 07:50  Vagari  阅读(213)  评论(0编辑  收藏  举报