P3709 大爷的字符串题
题目背景
在那遥远的西南有一所学校,
/被和谐部分/
然后去参加该省省选虐场,
然后某蒟蒻不会做,所以也出了一个字符串题:
题目描述
给你一个字符串 (a),每次询问一段区间的贡献。
贡献定义:
每次从这个区间中拿出一个字符 (x) ,然后把 (x) 从这个区间中删除,直到区间为空。你要维护一个集合 (S)。
- 如果 (S) 为空,你 (rp) 减 (1)。
- 如果 (S) 中有一个元素不小于 (x),则你 (rp) 减 (1),清空 (S)。
- 之后将 (x) 插入 (S)。
由于你是大爷,平时做过的题考试都会考到,所以每次询问你搞完这段区间的字符之后最多还有多少 (rp)?(rp) 初始为 (0)。
询问之间不互相影响~
输入格式
第一行两个整数 (n,m),表示字符串长度与询问次数。
之后一行 (n) 个数,第 (i) 个整数表示给出的字符串的第 (i) 个字符 (x_i)。
接下来 (m) 行,每行两个整数 (l, r),表示一次询问的区间。
输出格式
对于每次询问,输出一行一个整数表示答案。
输入输出样例
输入 #1
3 3
3 3 3
3 3
3 3
3 3
输出 #1
-1
-1
-1
说明/提示
数据规模与约定
- 对于 (10\%) 的数据,是样例。
- 对于另外 (10\%) 的数据,保证 (n,m le 100;)
- 对于另外 (10\%) 的数据,保证 (n,m le 10^3;)
- 对于另外 (10\%) 的数据,保证 (n,m le 10^4;)
- 对于另外 (10\%) 的数据,保证 (n,m le 10^5;)
- 对于 (100\%) 的数据,(1 leq n,m le 2 imes10^5,1 leq a_i leq 10^9,1 leq l, r leq n。)
保证数据像某省省选 day1T2 一样 sb,大家尽情用暴力水过题吧!
没事,你只要在一个好学校,就算这题只能拿到 10 分,也可以进队了。
Solution
唔,其实这是道语文题,题目要求
给定一个区间,求区间内众数的出现次数
为啥是这样,我们看这样一个样例
111122233345
12345/123/123/1
可以发现我们把序列排成一段一段的递增序列是最优的,每进入新的一段,(rp)就会-1
求段落数也就是求出现次数最多的数的出现次数,因为后面段落出现的数一定也在前面的段落中出现过
用莫队求解
我们用(cnt[x])表示(x)的出现次数,很明显在(add())中(ans=max(ans,cnt[x]))
但是删除的时候,可能会遇到这样一个问题,当前的(cnt[x])恰好就等于(ans),那我们能直接使(ans--)吗?不能!因为可能还有其他的(cnt[y])也等于(ans),删掉一个(x)不足以改变我们的答案
所以现在还要开一个数组(p[cnt]),表示出现次数为(cnt)的数字有多少个
在(remove())函数中,如果当前的(cnt[x]==ans)并且(p[cnt[x]]==1),我们才能使ans--
嗷,有一个细节,这道题的值域范围是(10^9),需要离散
Code
#include<bits/stdc++.h>
#define il inline
#define rg register
#define lol long long
#define in(i) (i=read())
using namespace std;
const int N=2e5+5;
int read() {
int ans=0,f=1; char i=getchar();
while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
return ans*f;
}
int n,m,k,block,ans;
int a[N],sum[N],cnt[N],p[N],b[N];
struct query{
int l,r,id,pos;
bool operator < (const query &a) const {
return pos==a.pos?r<a.r:pos<a.pos;
}
}t[N];
void add(int x) {
p[cnt[a[x]]]--;
cnt[a[x]]++;
p[cnt[a[x]]]++;
ans=max(ans,cnt[a[x]]);
}
void remove(int x) {
if(p[cnt[a[x]]]==1 && ans==cnt[a[x]]) ans--;
p[cnt[a[x]]]--;
cnt[a[x]]--;
p[cnt[a[x]]]++;
}
int main() {
in(n), in(m); block=3*sqrt(n);
for (rg int i=1;i<=n;i++) in(a[i]),b[i]=a[i];
sort(b+1,b+1+n); int len=unique(b+1,b+1+n)-b-1;
for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+len,a[i])-b;
for (rg int i=1,l,r;i<=m;i++) {
in(l), in(r);
t[i].l=l, t[i].r=r;
t[i].id=i;
t[i].pos=(l-1)/block+1;
}
sort(t+1,t+1+m);
for (rg int i=1,curl=1,curr=0;i<=m;i++) {
rg int l=t[i].l,r=t[i].r;
while(curl<l) remove(curl++);
while(curl>l) add(--curl);
while(curr<r) add(++curr);
while(curr>r) remove(curr--);
sum[t[i].id]=-ans;
}
for (rg int i=1;i<=m;i++) cout<<sum[i]<<endl;
}