P7554 [COCI2020-2021#6] Index-题解报告

1.前言

一道数据结构好题,不看题解之前能想出来思路对自己的数据结构提升水平会大大提升。

2.看题解前

由于打这个题之前打过一遍 Treap,又看到是一个只有查询的题,又看到了最值 h h h

因此第一感是个:

莫队+Treap+二分( O ( n n log ⁡ n ) O(n\sqrt{n}\log n) O(nn logn))。

氧化钙,好牛马的复杂度,空间也很假,还不好实现。。。

3.看题解后

我小心翼翼打开了题解区,值域分块+莫队。大悟的感觉。

然后打了很久。发现过不了样例,跟 @Others 神犇的题解对比了一下找了一下问题,一会儿就调出来了。

下次一定不ctj

4.思路

很显然,一眼莫队。

这个序列给的就是次数,所以说不用想就知道莫队维护的肯定也是次数。(数据范围也给了的)

根据以前打莫队的经验。维护一个次数的桶。

好,板子对吧,打完了,然后呢?怎么维护答案呢?

明显直接枚举便失去了时间复杂度优势,考虑加入值域分块。

不懂值域分块的可以百度一下,就是分块维护的是值域。

值域分块明显维护的便是次数的一个值域,块长取根号即可。

然后我们枚举的时候直接枚举从大到小每个值域分块的块,那么这个块满足条件的情况是什么呢?

我们假设这个块值域的最左端点为 L i L_i Li,这个块的值是 c n t i cnt_i cnti,以前已经有 s s s 这么多块内值了。

那么只有满足:

L i ≤ s + c n t i L_i\le s+cnt_i Lis+cnti

(这个看着有点雾,画一下样例应该能懂,也就相当于把题面的式子换了一下)。

答案才会在这个块里,然后如果满足,直接在块内暴力查找即可,就不用细讲了,原理和上述差不多。

总的复杂度显然是 O ( n n ) O(n\sqrt{n}) O(nn ) 的。

当然有哪里写得有问题或者没有怎么看懂的,也可以私信我。

5.代码

#include
using namespace std;
const int N=2e5+5;
const int M=2e5+5;
const int K=2e5+5;
int n,m,lenn,lenk;
int a[N],idx[N],idk[K];
int cnt[1005],t[K],kl[1005],kr[1005];
int ans[M];
struct Q{
	int l,r,k;
}q[M];
bool cmp(Q x,Q y){
	return idx[x.l]==idx[y.l]?x.r<y.r:idx[x.l]<idx[y.l];
}
void add(int x){
	cnt[idk[x]]++;
	t[x]++;
}
void sub(int x){
	cnt[idk[x]]--;
	t[x]--;
}
int Ans(){
	int res=0;
	for(int i=idk[200000];i>=1;i--){
		if(res+cnt[i]>=kl[i]){
			for(int j=kr[i];j>=kl[i];j--){
				if(res+t[j]>=j) return j;
				res+=t[j];
			}
		}
		res+=cnt[i]; 
	}
	return res;
}
int main(){
	scanf("%d %d",&n,&m);
	lenn=sqrt(n);
	lenk=sqrt(200000);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d %d",&q[i].l,&q[i].r),q[i].k=i,idx[i]=(i+lenn-1)/lenn;
	for(int i=1;i<=200000;i++) idk[i]=(i+lenk-1)/lenk;
	for(int i=1;i<=200000;i++) if(!kl[idk[i]]) kl[idk[i]]=i;
	for(int i=200000;i>=1;i--) if(!kr[idk[i]]) kr[idk[i]]=i;
	sort(q+1,q+1+m,cmp);
	int l=1,r=0;
	for(int i=1;i<=m;i++){
		while(q[i].l<l) add(a[--l]);
		while(q[i].l>l) sub(a[l++]);
		while(q[i].r<r) sub(a[r--]);
		while(q[i].r>r) add(a[++r]);
		ans[q[i].k]=Ans();
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
} 

你可能感兴趣的:(洛谷,数据结构,图论,算法)