码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ 2724】 [Violet 6]蒲公英

时间:2015-04-04 09:16:47      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:bzoj   oi   分块   

2724: [Violet 6]蒲公英

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 970  Solved: 319
[Submit][Status][Discuss]

Description

技术分享

Input

技术分享

修正一下

l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1

Output

技术分享

Sample Input

6 3
1 2 3 2 1 2
1 5
3 6
1 5

Sample Output

1
2
1

HINT

技术分享


修正下:


n <= 40000, m <= 50000

Source


分块。


首先把n个数分成sqrt(n)块,预处理出每一块的开头到他后面所有位置的答案,O(n*sqrt(n))。


对于每一个询问(l,r),我们把它分割成(l,L-1),(L,r),其中L是一个块的开始。


后者已经预处理过了,前者暴力枚举,用二分法计算他在(l,r)的出现次数,更新答案。

(为了求出现次数,我们需要把a[i]离散化,对于每个a[i]按照位置从左到右的顺序记录下来,然后就可以二分了)


时间复杂度O(m*sqrt(n)*logn+n*sqrt(n))

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#define pb push_back
#define M 40005
using namespace std;
int belong[M],cnt[M],n,m,tot,B,num;
vector<int> v[M];
struct data
{
	int hash,id;
}a[M];
struct Ans
{
	int ans,id;
}f[205][M];
struct Help
{
	int pos,v;
}b[M];
void read(int &tmp)
{
	tmp=0;
	char ch=getchar();
	int fu=1;
	for (;ch<'0'||ch>'9';ch=getchar())
		if (ch=='-') fu=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())
		tmp=tmp*10+ch-'0';
	tmp*=fu;
}
void Prepare()
{
	for (int i=1;i<=num;i++)
	{
		for (int j=(i-1)*B+1;j<=i*B;j++)
			belong[j]=i;
		for (int j=1;j<=tot;j++)
			cnt[j]=0;
		Ans x;
		x.ans=0,x.id=0;
		for (int j=(i-1)*B+1;j<=n;j++)
		{
			int h=a[j].hash;
			cnt[h]++;
			if (cnt[h]>x.ans||(cnt[h]==x.ans&&a[j].id<x.id))
				x.ans=cnt[h],x.id=a[j].id;
			f[i][j]=x;
		}
	}
}
bool cmp(Help a,Help b)
{
	if (b.v==a.v) return a.pos<b.pos;
	return a.v<b.v;
}
int Findd(int k,int l,int r,int w)
{
	if (l==r) return l;
	int m=(l+r)>>1;
	if (v[k][m]>w&&m-1>=0&&v[k][m-1]>=w) return Findd(k,l,m-1,w);
	if (v[k][m]<w) return Findd(k,m+1,r,w);
	return m;
}
int Findx(int k,int l,int r,int w)
{
	if (l==r) return l;
	int m=(l+r)>>1;
	if (v[k][m]<w&&m+1<v[k].size()&&v[k][m+1]<=w) return Findx(k,m+1,r,w);
	if (v[k][m]>w) return Findx(k,l,m-1,w);
	return m;
}
int Get(int k,int l,int r)
{
	int s=v[k].size();
	return Findx(k,0,s-1,r)-Findd(k,0,s-1,l)+1;
}
int Solve(int l,int r)
{
	int k=belong[l];
	if ((k-1)*B+1==l) return f[k][r].id;
	Ans x=f[k+1][r];
	for (int i=l;i<=min(k*B,r);i++)
	{
		int now=Get(a[i].hash,l,r);
		if (now>x.ans||(now==x.ans&&a[i].id<x.id))
			x.ans=now,x.id=a[i].id;
	}
	return x.id;
}
int main()
{
	scanf("%d%d",&n,&m);
	tot=0;
    for (int i=1;i<=n;i++)
	{
		read(a[i].id);
		b[i].v=a[i].id,b[i].pos=i;
	}
	sort(b+1,b+1+n,cmp);
	b[0].v=-10;
	for (int i=1;i<=n;i++)
		if (b[i].v==b[i-1].v) a[b[i].pos].hash=tot;
	    else a[b[i].pos].hash=++tot;
	for (int i=1;i<=n;i++)
		v[a[i].hash].pb(i);
	B=sqrt(n);
	num=(n+B-1)/B;
	Prepare();
	int ans=0;
	while (m--)
	{
		int l,r;
		read(l),read(r);
		l=(l+ans-1)%n+1,r=(r+ans-1)%n+1;
		if (l>r) swap(l,r);
		ans=Solve(l,r);
		printf("%d\n",ans);
	}
	return 0;
}

技术分享


感悟:

1.二分写错;

Solve中要注意(l,r)可能不足一块,所以循环到min(k*B,r)

【BZOJ 2724】 [Violet 6]蒲公英

标签:bzoj   oi   分块   

原文地址:http://blog.csdn.net/regina8023/article/details/44860807

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!