【BZOJ2724】[Violet 6]蒲公英 分块+二分

【BZOJ2724】[Violet 6]蒲公英

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

题解:分块还是练脑子啊~

结论:一个区间的众数要么是区间中一个块的众数,要么是块外的任意一个数。

这就告诉我们需要预处理出任意两个块之间的所有数的众数,这个可以用离散化+桶+扫一遍实现。

那么对于询问[l,r]我们假设其中最大的连续的块是[ll,rr],那么我们已知了[ll,rr]中的众数,如何判断[l,ll),(rr,r]中的数是不是众数呢?

既然已经将所有数离散化了,我们就可以考虑记录每个数出现的位置。我们将每个数出现的位置从左到右用vector存起来,然后查询的时候二分一下,就知道了这个数在[l,r]中出现了多少次,用它来更新答案就行了。

sqrt(n/logn)大法好~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=40010;
int n,m,nm,B,mx,ans;
int v[maxn],st[maxn],ref[maxn];
int s[810][810];
vector<int> pos[maxn];
struct node
{
	int org,val;
}num[maxn];
bool cmp(node a,node b)
{
	return a.val<b.val;
}
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void query(int a,int b,int x)
{
	if(!x||st[x])	return ;
	int l=0,r=pos[x].size()-1,mid,c,d;
	while(l<r)
	{
		mid=l+r>>1;
		if(pos[x][mid]>=a)	r=mid;
		else	l=mid+1;
	}
	c=r;
	l=0,r=pos[x].size();
	while(l<r)
	{
		mid=l+r>>1;
		if(pos[x][mid]<=b)	l=mid+1;
		else	r=mid;
	}
	d=l-1,st[x]=d-c+1;
	if(st[x]>st[mx]||(st[x]==st[mx]&&x<mx))	mx=x;
}
int main()
{
	//freopen("bz2724.in","r",stdin);
	n=rd(),m=rd();
	int i,j,a,b,c,d;
	for(i=0;i<n;i++)	num[i].val=rd(),num[i].org=i;
	sort(num,num+n,cmp);
	for(i=0;i<n;i++)
	{
		if(!i||num[i].val>num[i-1].val)	ref[++nm]=num[i].val;
		v[num[i].org]=nm;
	}
	B=int(sqrt(double(n)/log(n)));
	for(i=0;i<n;i++)	pos[v[i]].push_back(i);
	for(i=0;i*B<n;i++)
	{
		memset(st,0,sizeof(st));
		for(mx=0,j=i*B;j<n;j++)
		{
			st[v[j]]++;
			if(st[v[j]]>st[mx]||(st[v[j]]==st[mx]&&v[j]<mx))	mx=v[j];
			s[i][j/B]=mx;
		}
	}
	memset(st,0,sizeof(st));
	for(i=1;i<=m;i++)
	{
		a=(rd()+ans-1+n)%n,b=(rd()+ans-1+n)%n;
		if(a>b)	swap(a,b);
		c=a/B,d=b/B;
		if(c==d)
		{
			for(mx=0,j=a;j<=b;j++)
			{
				st[v[j]]++;
				if(st[v[j]]>st[mx]||(st[v[j]]==st[mx]&&v[j]<mx))	mx=v[j];
			}
			ans=ref[mx],printf("%d\n",ans);
			for(j=a;j<=b;j++)	st[v[j]]--;
			continue;
		}
		mx=0,query(a,b,s[c+1][d-1]);
		for(j=a;j<c*B+B;j++)	query(a,b,v[j]);
		for(j=d*B;j<=b;j++)	query(a,b,v[j]);
		ans=ref[mx],printf("%d\n",ans);
		st[s[c+1][d-1]]=0;
		for(j=a;j<c*B+B;j++)	st[v[j]]=0;
		for(j=d*B;j<=b;j++)	st[v[j]]=0;
	}
	return 0;
}
时间: 2024-10-07 05:02:15

【BZOJ2724】[Violet 6]蒲公英 分块+二分的相关文章

BZOJ2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 795  Solved: 248[Submit][Status] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input Sample Output HINT 修正下: n <= 40000, m <= 50000 S

【bzoj2724】[Violet 6]蒲公英 分块+STL-vector

题目描述 输入 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 输出 样例输入 6 3 1 2 3 2 1 2 1 5 3 6 1 5 样例输出 1 2 1 题解 分块+STL-vector 一个显而易见的结论:区间众数一定是一段连续的块的众数或块外的数,证明略(逃 先把数据离散化,然后分块预处理出f[i][j],表示从块i到块j的众数位置.具体实现的话直接开个桶存一下就好了. 然后考虑询问,整块的直接拿出来求一下出现次

bzoj2724: [Violet 6]蒲公英(分块)

传送门 md调了一个晚上最后发现竟然是空间开小了……明明算出来够的…… 讲真其实我以前不太瞧得起分块,觉得这种基于暴力的数据结构一点美感都没有.然而今天做了这道分块的题才发现分块的暴力之美(如果我空间没有开小就更美了) 我们先将整个数组分块,设块的大小为$T$ 我们先预处理出所有以块边界为端点的区间的答案,即$ans[L][R]$代表着第$L$块到第$R$块的序列所代表的答案.这个可以$O(n*n/T)$预处理 然后我们先将所有的数给离散化,然后对每一个值都开一个vector,记录这个值在数组中

【分块】bzoj2724 [Violet 6]蒲公英

分块,离散化,预处理出: ①前i块中x出现的次数(差分): ②第i块到第j块中的众数是谁,出现了多少次. 询问的时候,对于整块的部分直接获得答案:对于零散的部分,暴力统计每个数出现的次数,加上差分的结果,尝试更新ans. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int n,m,sum,sz,n

bzoj2724: [Violet 6]蒲公英(离散化+分块)

我好弱啊..这题调了2天QwQ 题目大意:给定一个长度为n(n<=40000)的序列,m(m<=50000)次询问l~r之间出现次数最多的数.(区间众数) 这题如果用主席树就可以不用处理一堆前缀和..蓝鹅我不会~T_T~. 把序列n分成sqrt(n)块,先把所有数离散化,预处理出poi[i][j]表示第i块到第j块的众数(即出现次数最多的数). 询问有两种情况: 第一种情况是l~r在某个块中,那么直接扫一遍求出众数,效率O(sqrt(n)). 第二种情况是l~r在多个块中,l在x块,r在y块,

BZOJ 2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1633  Solved: 563[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 Outp

【BZOJ 2724】 [Violet 6]蒲公英

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 Out

【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1908  Solved: 678 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 <= 4

「Violet」蒲公英

「Violet」蒲公英 传送门 区间众数,强制在线. 分块经典题. 像这题一样预处理,然后就直接爆搞,复杂度 \(O(n \sqrt n)\) 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".ou