首页 > 其他分享 >蒲公英(分块)

蒲公英(分块)

时间:2024-04-19 12:35:17浏览次数:18  
标签:le tong 分块 int res ans 蒲公英

[Violet] 蒲公英

题目背景

亲爱的哥哥:

你在那个城市里面过得好吗?

我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的……

最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!

哥哥你要快点回来哦!

爱你的妹妹 Violet

Azure 读完这封信之后微笑了一下。

“蒲公英吗……”

题目描述

在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。

为了简化起见,我们把所有的蒲公英看成一个长度为 \(n\) 的序列 \(\{a_1,a_2..a_n\}\),其中 \(a_i\) 为一个正整数,表示第 \(i\) 棵蒲公英的种类编号。

而每次询问一个区间 \([l, r]\),你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。

注意,你的算法必须是在线的

输入格式

第一行有两个整数,分别表示蒲公英的数量 \(n\) 和询问次数 \(m\)。

第二行有 \(n\) 个整数,第 \(i\) 个整数表示第 \(i\) 棵蒲公英的种类 \(a_i\)。

接下来 \(m\) 行,每行两个整数 \(l_0, r_0\),表示一次询问。输入是加密的,解密方法如下:

令上次询问的结果为 \(x\)(如果这是第一次询问,则 \(x = 0\)),设 \(l=((l_0+x-1)\bmod n) + 1,r=((r_0+x-1) \bmod n) + 1\)。如果 \(l > r\),则交换 \(l, r\)。
最终的询问区间为计算后的 \([l, r]\)。

输出格式

对于每次询问,输出一行一个整数表示答案。

样例 #1

样例输入 #1

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

样例输出 #1

1 
2 
1

提示

数据规模与约定

  • 对于 \(20\%\) 的数据,保证 \(n,m \le 3000\)。
  • 对于 \(100\%\) 的数据,保证 \(1\le n \le 40000\),\(1\le m \le 50000\),\(1\le a_i \le 10^9\),\(1 \leq l_0, r_0 \leq n\)。

我们可以先浅浅的打一下暴力

点击查看代码
#include <bits/stdc++.h>
//#define int long long
using namespace std;
const int N =40000,M=40000+5;
int n,m,a[M];
int zh[M][3005];
map <int,int> mp,fmp;
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>m;
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(!mp[a[i]])mp[a[i]]=++cnt,fmp[cnt]=a[i];
		for(int j=1;j<=cnt;j++)
		{
			zh[i][j]=zh[i-1][j];
		}
		zh[i][mp[a[i]]]++;
	}
//	cout<<cnt;
	int l,r,ans=0;
	for(int i=1;i<=m;i++)
	{
		cin>>l>>r;
		l=(l+ans-1)%n+1;
		r=(r+ans-1)%n+1;
		if(l>r)swap(l,r);
		int tms=0;
		for(int j=1;j<=cnt;j++)
		{
			if(zh[r][j]-zh[l-1][j]>tms)
			{
				ans=fmp[j];
				tms=zh[r][j]-zh[l-1][j];
			}else if(zh[r][j]-zh[l-1][j]==tms)
			{
				ans=min(fmp[j],ans);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

会超时,以为他在求前缀和时候占用的时间太长,首先无论如何要离散化一下(有本事你不),这时候我们会想到分块,每个块中存种类最多的那个答案,但是会有多个块连在一起的区间,所以开一个数组mp记录从\(i\)到\(j\)块中的答案,我们可以暴力预处理一下,然后考虑到有散块,这部分暴力就行,但还要预处理一下整块中存在的a[i]数量,开一个数组sum记录从\(i\)开始\(a[i]\)的出现次数,与散块相加,统计,选出最优的即可

点击查看代码
#include <bits/stdc++.h>
//#define int long long
using namespace std;
const int N =40000,M=40000+5,G=505;
int n,m,a[M],tong[M],st[G],en[G],mp[G][M],sum[G][M],sq,belong[M];
int read()
{
	int f=1,x=0;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-f;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
void init()
{
	sq=sqrt(n);
	for(int i=1;i<=sq;i++)
	{
		st[i]=n/sq*(i-1)+1;
		en[i]=n/sq*i;
	}
	en[sq]=n;
	for(int i=1;i<=sq;i++)
	{
		for(int j=st[i];j<=en[i];j++)
		{
			belong[j]=i;
		}
//		size[i]=en[i]-st[i]+1;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=belong[i];j<=sq;j++)
		{
			sum[j][a[i]]++;
		}
	}
	for(int i=1;i<=sq;i++)
	{
		memset(tong,0,sizeof(tong));
		for(int j=i;j<=sq;j++)
		{
			mp[i][j]=mp[i][j-1];
			int res=mp[i][j];
			for(int k=st[j];k<=en[j];k++)
			{
				tong[a[k]]++;
				if(tong[a[k]]>tong[res]||(tong[res]==tong[a[k]]&&a[k]<res))
				{
					res=a[k];
				}
			}
			mp[i][j]=res;
//			cout<<"&&"<<st[i]<<" "<<en[j]<<" "<<res<<endl;
		}
	}
	memset(tong,0,sizeof(tong));
}
int query(int l,int r)
{	
	int res=0;
	if(belong[l]==belong[r])
	{
		for(int i=l;i<=r;i++)
		{
			tong[a[i]]++;
			if(tong[a[i]]>tong[res]||(tong[res]==tong[a[i]]&&a[i]<res))
			{
				res=a[i];
			}
		}
		for(int i=l;i<=r;i++)tong[a[i]]=0;			
	}else
	{
		int tmpres=mp[belong[l]+1][belong[r]-1];
		int tmpans=sum[belong[r]-1][tmpres]-sum[belong[l]][tmpres];
//		cout<<tmpans<<"^^^^";
		for(int i=l;i<=en[belong[l]];i++)
		{
			if(!tong[a[i]])
			{
				tong[a[i]]+=sum[belong[r]-1][a[i]]-sum[belong[l]][a[i]];
			}
			if(a[i]==tmpres)tmpans++;
		}
		for(int i=st[belong[r]];i<=r;i++)
		{
			if(!tong[a[i]])
			{
				tong[a[i]]+=sum[belong[r]-1][a[i]]-sum[belong[l]][a[i]];
			}
			if(a[i]==tmpres)tmpans++;
		}
		for(int i=l;i<=en[belong[l]];i++)
		{
			tong[a[i]]++;
			if(tong[a[i]]>tong[res]||(tong[res]==tong[a[i]]&&a[i]<res))
			{
				res=a[i];
			}
		}
		for(int i=st[belong[r]];i<=r;i++)
		{
			tong[a[i]]++;
			if(tong[a[i]]>tong[res]||(tong[res]==tong[a[i]]&&a[i]<res))
			{
				res=a[i];
			}			
		}
		if(tmpans>tong[res]||(tmpans==tong[res]&&tmpres<res))
		{
			res=tmpres;
//			cout<<"%%"<<endl;
		}
		for(int i=l;i<=en[belong[l]];i++)tong[a[i]]=0;	
		for(int i=st[belong[r]];i<=r;i++)tong[a[i]]=0;	
	}	
	return res;
}
int b[M];
void write(int x)
{
	if(x>=10)write(x/10);
	putchar(x%10+'0');
}
signed main()
{
//	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//	freopen("P4168_1.in","r",stdin);
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	int tot=unique(b+1,b+1+n)-b-1;
	for(int i=1;i<=n;i++)
	{
		a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
	}	
	init();
//	cout<<cnt;
	int l,r,ans=0;
	for(int i=1;i<=m;i++)
	{
		l=read();r=read();
		l=(l+ans-1)%n+1;
		r=(r+ans-1)%n+1;
//		cout<<l<<" "<<r<<endl;
		if(l>r)swap(l,r);
		ans=query(l,r);
		ans=b[ans];
		write(ans);
//		ans=b[ans];
		putchar('\n');
	}
	return 0;
}

标签:le,tong,分块,int,res,ans,蒲公英
From: https://www.cnblogs.com/wlesq/p/18145570

相关文章

  • 分块板子
    预处理voidinit(){clean();scanf("%lld",&n);for(i=1;i<=n;i++)scanf("%lld",&a[i]);sq=sqrt(n);for(i=1;i<=sq;i++){st[i]=n/sq*(i-1)+1;ed[i]=n/sq*i;}ed[sq]=n;for(i=1;i<......
  • 分块--解决区间问题
    什么时候用分块?当你发现正常数据结构无法解决的时候(比如维度特别多,很不方便或者炸空间),或者复杂到要3个$log$以上才能解决时。(主要还是得看数据范围,分块的做法一般都是$O(\sqrt{n})$及以上的如何分块?定一个块长$B$,整个序列就会被分成$\floor{n/B}$块,对于末尾的不......
  • 断点续传-视频文件的分块和合并
    目录一,前言二,断点续传三,断点续传流程:四,java代码测试分块和合并视频文件分块: 视频文件合并:五,应用(简单了解)一,前言通常视频文件都比较大,项目中需要满足大文件的上传要求,http协议本身对上传文件大小没有限制,但是客户的网络质量,电脑硬件环境等参差不齐,如果一个大的......
  • 分块与莫队
    不沾树的博客变短了好多。分块例题这道题显然可以使用线段树乱搞过去,不过为了给主角面子我们假设我们不会做。对于一些难以使用数据结构维护答案的序列问题,我们考虑暴力。但是暴力太慢了,于是人们提出了分块。分块,就是把序列分成许多的小段,通过一些神秘的处理实现优化暴力。......
  • 【学习笔记】数论分块
    先看一个例子:给出正整数\(n(n\leq10^{12})\),计算:\[\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\]如果直接暴力,复杂度为\(O(n)\),无法在1s内通过,但使用数论分块(整除分块)可以将复杂度降至\(O(\sqrt{n})\)。先看个例子,当\(n=100\)时,\(i\)和\(\lfloor\frac{n}{i}\r......
  • 重生之分块修炼
    \(\textit{2024.1.2711:45}\),召唤最强从者——职阶为\(\textit{Oier}\)的\(\textit{Soul}\)_\(\textit{Love}\)协助学习分块。\(\textit{2024.1.2714:30}\),从《分块(块状数组)(从入门到出门右拐)》开始。重修分块。\(\textit{2024.1.2811:20-11:46}\),拿P3372【模板】......
  • 内存分块!
    这是我在学习这方面知识的笔记,主要是网课上老师讲的内容和一些自己的想法,整理了一下,希望对学习这方面知识的小伙伴有帮助:)1.内存条全局区:    全局变量    静态变量  (static关键字)    常量:      字符串常量      con......
  • 2024-4-4 分块补题
    P3203[HNOI2010]弹飞绵羊记录每个位置跳出当前块所需要的步数和跳出的位置。从后往前统计#include<bits/stdc++.h>#definemaxn200100usingnamespacestd;intn,m,len;intpos[maxn],k[maxn];intnxt[maxn],stp[maxn];structfk{intl,r;}a[maxn];intread(){......
  • 2024/4/4 分块补题
    2024/4/4分块补题P3203[HNOI2010]弹飞绵羊分块跳跳跳,核心是每次跳出当前块,用\(to[i]\)表示跳到的位置。#include<bits/stdc++.h>usingnamespacestd;#defineldlongdoubletemplate<typenameT>inlineTread(){Tx=0;charch=getchar();boolfl=false;......
  • 数论分块学习笔记
    数论分块学习笔记性质数论分块用于快速计算含有除法向下取整的和式,即形如\(\sum_{i=1}^nf(i)g(\lfloor\frac{n}{i}\rfloor)\)的式子。当预处理出\(f\)的前缀和时,数论分块可以在\(O(\sqrt{n})\)的时间复杂度下计算上述和式的值。求解引理\(1\):\(\foralla,b,c\in\math......