题目其实是和这道题目一样的 https://www.luogu.com.cn/problem/P1997
题目中有一句话很重要将这段区间搞完后最多还会剩下多少 rp,对于题目给出的规则我们可以理解为
- 如果区间不为空,答案为 0
- 存在 a∈ S,如果 a>=x ,那么清空 S,插入 a
- 任意 a∈ S,如果 a<x,那么直接插入 a
规则可以理解为构造任意个严格单调上升子序列,但是为了使最后的答案最大,我们要保持构造的子序列的数量尽可能少,举个例子:我们已经构造了如下三个子序列:
- cd
- aef
- b
但是他们可以变成一个,不满足数量最少的条件,但是区间中的任意数字我们都可以打乱顺序来构造,所以只有遇到相同元素的时候,才迫不得已将 rp-1,所以题意转化为求区间内的众数的大小
下面简述算法实现过程,由于 a[] 的值过大,如果要处理众数必须要利用桶,所以我们先将他们离散化
在整个过程中应用莫队,但是莫队要维护两个值,一个是 x 出现的次数,另一个是出现次数为 x 一共有多少个
const int N=2e5+5;
int n,m;
int i,j,k;
int a[N];
int vis[N],now,ans[N],app[N]; //vis[x] x出现的次数,app[x]出现 x 次的数量
struct Node
{
int l,r;
int bel,id;
void read(){ sdd(l,r); }
}q[N];
vector<int> v;
bool cmp(Node a,Node b)
{
return a.bel==b.bel?a.r<b.r:a.l<b.l;
}
void mo()
{
int block=sqrt(n);
for(int i=1;i<=m;i++) q[i].id=i,q[i].bel=q[i].l/block+1;
sort(q+1,q+1+m,cmp);
}
int getid(int x)
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void add(int pos)
{
int x=a[pos];
app[vis[x]]--;
app[++vis[x]]++;
now=max(now,vis[x]);
}
void del(int pos)
{
int x=a[pos];
if(now==vis[x] && app[vis[x]]==1) now--;
app[vis[x]]--;
app[--vis[x]]++;
}
int main()
{
//IOS;
while(~sdd(n,m)){
for(int i=1;i<=n;i++) sd(a[i]),v.pb(a[i]);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++) a[i]=getid(a[i]);
for(int i=1;i<=m;i++) q[i].read();
mo();
int l=1,r=0; now=0;
for(int i=1;i<=m;i++){
while(l>q[i].l) add(--l);
while(r<q[i].r) add(++r);
while(r>q[i].r) del(r--);
while(l<q[i].l) del(l++);
ans[q[i].id]=-now;
}
for(int i=1;i<=m;i++) pd(ans[i]);
}
PAUSE;
return 0;
}