[题解]UVA11235 Frequent values

UVA11235 Frequent values

没看到多测调了半天

每组数据给定\(n,q\)。接下来给出一个长度为\(n\)不降序列\(A\)。接下来\(q\)次询问,每次询问给定\(l,r\),求\(A_{l\sim r}\)中出现最多的那个数出现了多少次。

\(1\le n,q \le 10^5\)


序列不降,意味着一个数在序列中一定是连续存在的。

那么我们可以把连续相同的元素分成一段(游程编码)。

设一共分了\(len\)段,第\(i\)段的左边界是\(l\),右边界是\(r\)\(A_i\)在第\(num[i]\)段。

查询时,对于输入的\(x,y\)。我们的答案就是下面三种情况的最大值:

  • \(x\sim x\)所在组的右边界,即\(r[num[x]]-x+1\)
  • \(y\)所在组的左边界\(\sim y\),即\(y-l[num[y]]+1\)
  • \(x\)所在组的下一组\(\sim y\)所在组的上一组中,最大组的大小,即\(\max\limits_{num[x]<i<num[y]}(r[i]-l[i]+1)\)。这一操作可以用ST表来维护。

实现细节:

  • 如果\(num[x]=num[y]\)\(x,y\)在同一组),则直接输出\(y-x+1\)
  • 否则,答案就是上面\(3\)种情况的最大值,但需要注意调用query(num[x]+1,num[y]-1),可能会出现\(num[x]+1>num[y]-1\)的情况,此时\(query\)需要返回\(0\)

每个测试点时间复杂度\(O(n\log n+q)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,q,a[100010];
int siz,cur=INT_MIN;
int l[100010],r[100010],lg[100010];
int len,num[100010];
int maxx[100010][30];
void init(){
	lg[0]=-1;
	for(int i=1;i<=len;i++)
		lg[i]=lg[i/2]+1,maxx[i][0]=r[i]-l[i]+1;
	for(int i=1;i<=lg[len];i++){
		for(int j=1;j+(1<<i)-1<=len;j++){
			maxx[j][i]=max(maxx[j][i-1],maxx[j+(1<<(i-1))][i-1]);
		}
	}
}
int query(int l,int r){
	if(l>r) return 0;
	int t=lg[r-l+1];
	return max(maxx[l][t],maxx[r-(1<<t)+1][t]);
}
int main(){
	while(cin>>n>>q){
		len=0;
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++){
			if(a[i]!=cur){
				r[len]=i-1;
				l[++len]=i;
				cur=a[i];
			}
			num[i]=len;
		}
		r[len]=n;
		init();
		while(q--){
			int x,y;
			cin>>x>>y;
			if(num[x]==num[y]) cout<<y-x+1<<endl;
			else cout<<max(max(r[num[x]]-x+1,y-l[num[y]]+1),
				query(num[x]+1,num[y]-1))<<endl;
		}
	}
	return 0;
}
posted @ 2024-06-02 14:13  Sinktank  阅读(11)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.