【loj6285】 数列分块入门 9

原题

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cstdlib>
#define ll long long
#define inf 0x3f3f3f3f
#define N 1000009
using namespace std;

map<int,int>mp;//离散化
vector<int> vec[N];//记录每个值出现的位置
int blo[N],v[N],val[N],cnt[N];
int f[505][505];//记录(i,j)的众数
int id,len,n;


ll read()
{
	char ch=getchar();ll f=1,ret=0;
	while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
	return f*ret;
}

void pre(int x)//预处理从x~i(i=x~n)的众数
{
	int mx=0,cur=0;
	memset(cnt,0,sizeof(cnt));
	for (int i=(x-1)*len+1;i<=n;i++)
	{
		int pos=blo[i];
		cnt[v[i]]++;
		if (cnt[v[i]]>mx||(cnt[v[i]]==mx&&val[v[i]]<val[cur]))//如果v[i]出现的次数多,或者次数一样多但值小
			cur=v[i],mx=cnt[v[i]];
		f[x][pos]=cur;//在(x,blo[i])的块间众数更新
	}
}

int ask(int l,int r,int x)//询问在区间(l,r)之间,数值为x的数出现的次数
{return (upper_bound(vec[x].begin(),vec[x].end(),r)-lower_bound(vec[x].begin(),vec[x].end(),l));}

int query(int l,int r)
{
	int p=blo[l],q=blo[r],ans=f[p+1][q-1],mx=0;
	mx=ask(l,r,ans);//先找在块(blo[l]+1,blo[r]-1)的众数在区间(l,r)之间出现的次数
	for (int i=l;i<=min(p*len,r);i++)//然后我们暴力处理从整块两边多余的部分
	{
		int t=ask(l,r,v[i]);
		if (t>mx||(t==mx&&val[ans]>val[v[i]])) mx=t,ans=v[i];
	}
	if (p!=q)
		for (int i=(q-1)*len+1;i<=r;i++)
		{
			int t=ask(l,r,v[i]);
			if (t>mx||(t==mx&&val[ans]>val[v[i]])) mx=t,ans=v[i];
		}
	return val[ans];
}

int main()
{
	n=read();len=200;
	for (int i=1;i<=n;i++)
	{
		v[i]=read();
		if (!mp[v[i]])//如果这个值并没有离散化,离散化
		{
			mp[v[i]]=++id;
			val[id]=v[i];
		}
		v[i]=mp[v[i]];
		vec[v[i]].push_back(i);
	}
	for (int i=1;i<=n;i++) blo[i]=(i-1)/len+1;
	for (int i=1;i<=blo[n];i++) pre(i);
	for (int i=1;i<=n;i++)
	{
		int l=read(),r=read();
		if (l>r) swap(l,r);
		printf("%d\n",query(l,r));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dadatu_zhao/article/details/80559189
今日推荐