uva11235:Frequent values (ST表)

题目大意:给出一个非降序排列的整数数组,a1,a2,…,an,你的任务是对于一系列的询问(i,j),回答ai,ai + 1,…,aj中出现次数最多的值所出现的次数。

输入格式:多组数据,每组数据第一行输入n和q,(1 <= n ,q <= 100000)。第二行包含n个非降序排列的整数a1,a2,…,an (-100000 <= ai <= 100000)。以下q行每行包括两个整数i和j (1 <= i <= j <= n),输入结束标准为n = 0。

做法分析:注意题目说到给出的序列是非降序的,这意味着中间相同的元素会排在一起,如果不是非降序排列的还真不好做。既然是一团在一起的,可以将一团数据缩在一起,用一个二元组表示(a,b),表示值为a的元素出现b次。

对于每一对i,j询问,第i个元素所在的团,和第j个所在的团是不完整的,而中间所有的团都是完整的,先求得两边两个不完整的团的大小:ans = max(R[i] - i + 1,j - L[j] +1)。中间完整的团的查询可以用RMQ。注意特判i,j都在一个团的情况,以及一共只有两个团的情况。

这里可以用下标映射,也可以用值映射,因为下标映射我写炸了,改成了值映射。

#include<bits/stdc++.h> 
using namespace std;
#define pii pair<int,int>
const int maxn = 1e5 + 10;
const int mx = 18;
int n,q;
int val[maxn];
int lef[maxn * 3],rig[maxn * 3],mp[3 * maxn];
int st[maxn - 1][mx - 1];
vector<pii> g;
int Hash(int x) {
	return x + 100000;	
}
void init() {
	memset(lef,-1,sizeof(lef));
	memset(rig,-1,sizeof(rig));
	memset(val,-1,sizeof(val));
	memset(mp,-1,sizeof(mp));
	memset(st,0,sizeof(st));	
	g.clear();
}
int main() {
	while(scanf("%d",&n) && n) {
		scanf("%d",&q);
		init();
		int last = 0x3f3f3f3f;
		for(int i = 1; i <= n; i++) {
			scanf("%d",&val[i]);
			if(val[i] == last)
				rig[Hash(val[i])] = i;
			else {
				if(i != 1) {
					g.push_back(pii(val[i - 1],rig[Hash(val[i - 1])] - lef[Hash(val[i - 1])] + 1));
					mp[Hash(val[i - 1])] = g.size() - 1;
				}
				last = val[i];
				lef[Hash(val[i])] = i;
				rig[Hash(val[i])] = i;
			}
		}
		
		rig[Hash(val[n])] = n; 
		g.push_back(pii(val[n],rig[Hash(val[n])] - lef[Hash(val[n])] + 1));
		mp[Hash(val[n])] = g.size() - 1;
		
		int len = g.size() - 1;
		for(int i = 0; i <= len; i++) 
			st[i][0] = g[i].second;
		for(int j = 1; (1 << j) <= len; j++)
			for(int i = 0; i + (1 << j) - 1 <= len; i++)
				st[i][j] = max(st[i][j - 1],st[i + (1 << (j - 1))][j - 1]);
				
		for(int i = 1; i <= q; i++) {
			int l,r;
			int ans = 0;
			scanf("%d%d",&l,&r);
			if(val[l] == val[r])
				ans = r - l + 1;
			else {
				int vl = Hash(val[l]),vr = Hash(val[r]); 
				ans = max(rig[vl] - l + 1,r - lef[vr] + 1);
				int sta = mp[vl] + 1, en = mp[vr] - 1;
				if(sta <= en) {
					int li = en - sta + 1;
					int k = (int) (log((double)li) / log(2.0));
					ans = max(ans,max(st[sta][k],st[en - (1 << k) + 1][k]));
				}
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}	

猜你喜欢

转载自blog.csdn.net/qq_41997978/article/details/89738899