题意:
这题...题意是重点!!!作为一道语文题,这道题的题意使难度上升了很多(其实重点是因为我语文差/kk
给你一个字符串 (a) (其实不是字符串,就是一个数组),每次询问一段区间的贡献。
区间的贡献定义:
初始 (rp=0)。
每次从这个区间中拿出一个字符 (x) (数),然后把 (x) 从这个区间中删除,直到区间为空。你要维护一个集合 (S)。
-
如果 (S) 为空,你 (rp-1)。
-
如果 (S) 中有一个元素大于等于 (x),则你 (rp-1),清空 (S)。
-
之后将 (x) 插入 (S)。
要求使得 (rp) 最大。
数据范围:(1 leq n,m le 2 imes10^5)。
Solution:
由这个数据范围及只需查询很容易想到 莫队。
题意看起来比较麻烦,我一开始也被搞蒙了,后经过大佬@快乐的疯烁及神仙同桌@子落楸枰指点,才懂。
举个栗子:
比如题目编号 1 2 3 4 5 6 7
难度分别为 1 2 2 3 3 3 3
要查询 1-4,2-5,3-6
手摸得知,答案为 -2,-2,-3
插入顺序:
查询点1:以编号为 1,2,4,3 顺序插入最优。
查询点2:以编号为 2,4,3,5 顺序插入最优。
查询点3:以编号为 3,4,5,6 顺序插入最优。
由此,我们可以发现两个结论:
-
答案正是查询区间众数(与P1997 faebdc 的烦恼一样,是双倍经验)
-
插入时我们并不是从左到右插的,而是先全部是不同大小的插入,所以后面查询的时候是要先改 (r),再改 (l) 的!!!(不然你会得到 (80) 的高分,我就是因为这个调了两个晚自修 /fad)。
Code:
代码就很简单了。
/*
* @Author: FuTianyu
* @Date: 2020-11-05 18:07:14
* @Last Modified by: FuTianyu
* @Last Modified time: 2020-11-05 20:06:21
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define debug() puts("fty")
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)
/*
快读快输
*/
const int N=2e5+5;
int n,m,a[N],b[N],kc,kuai[N],tong[N],sum[N],ans,Ans[N];
/*
a_i表示原始数组,由于很大,需要离散化,b_i即为离散化后的数组.
tong_i表示第i个数在区间内出现的个数,sum_i表示区间内出现个数为i的个数.
*/
struct node{
int l,r,id;
}cun[N];
bool cmp(node x,node y){
return kuai[x.l]==kuai[y.l]?x.r<y.r:kuai[x.l]<kuai[y.l];
}
void del(int x){
sum[tong[b[x]]]--;
if(ans==tong[b[x]]&&sum[tong[b[x]]]==0) ans--;
sum[--tong[b[x]]]++;
}
void add(int x){
sum[tong[b[x]]]--;
if(ans==tong[b[x]]) ans++;
sum[++tong[b[x]]]++;
}
signed main(){
n=read();
m=read();
kc=sqrt(n);
FOR(i,1,n){
a[i]=read();
b[i]=a[i];
kuai[i]=(i-1)/kc+1;
}
sort(a+1,a+1+n);
int len=unique(a+1,a+1+n)-a-1;
FOR(i,1,n) b[i]=lower_bound(a+1,a+1+len,b[i])-a;
FOR(i,1,m){
cun[i].l=read();
cun[i].r=read();
cun[i].id=i;
}
sort(cun+1,cun+1+m,cmp);
int l=1,r=0;
FOR(i,1,m){
int L=cun[i].l;
int R=cun[i].r;
while(r>R) del(r--);
while(r<R) add(++r);
while(l<L) del(l++);
while(l>L) add(--l);
Ans[cun[i].id]=-ans;
}
FOR(i,1,m){
write(Ans[i]);
puts("");
}
return 0;
}