[Violet]蒲公英 分块

Code:

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
void setIO(string a){ freopen((a+".in").c_str(),"r",stdin); }

const int maxn=40000+5;
int n,m,block;
int col[maxn],A[maxn],belong[maxn],bucket[maxn];
int prefix[300][maxn];
int best[300][300];
vector<int>position[maxn],solve;
int st(int i){ return (i-1)*block+1; }
int ed(int i){ return min(i*block,n);}
int main(){
	//setIO("input");
	scanf("%d%d",&n,&m);
	block=sqrt(n);
	for(int i=1;i<=n;++i) {
		scanf("%d",&col[i]);
		A[i]=col[i];
		belong[i]=(i-1)/block+1;
	}
	sort(A+1,A+1+n);
    for(int i=1;i<=n;++i) {
    	col[i]=lower_bound(A+1,A+1+n,col[i])-A;
    	prefix[belong[i]][col[i]]+=1;
    }
    for(int i=1;i<=belong[n];++i)
    	for(int j=1;j<=n;++j) prefix[i][j]+=prefix[i-1][j];

    for(int length=1;length<=belong[n];++length)
    	for(int i=1;i+length-1<=belong[n];++i)
    	{
    		int j=i+length-1;
    		int tmp=0,cur=0;
     		for(int k=st(i);k<=ed(i);++k)          //枚举 i 中颜色
     		{
    			int delta=prefix[j][col[k]]-prefix[i-1][col[k]];
    			if(delta >= tmp){
    				if(delta>tmp) tmp=delta,cur=col[k];
    				else if(col[k]<cur) cur=col[k];
    			}
    		}
    		for(int k=st(j);k<=ed(j);++k){         //枚举 j 中颜色
    			int delta=prefix[j][col[k]]-prefix[i-1][col[k]];
    			if(delta >= tmp){
    				if(delta>tmp) tmp=delta,cur=col[k];
    				else if(col[k]<cur) cur=col[k];
    			}
    		}

    		if(j>i){
    			int delta;
    			delta=prefix[j][best[i+1][j]]-prefix[i-1][best[i+1][j]];
    			if(delta>=tmp){
    				if(delta>tmp) tmp=delta, cur=best[i+1][j];
    				else if(best[i+1][j]<cur) cur=best[i+1][j];
    			}

    			delta=prefix[j][best[i][j-1]]-prefix[i-1][best[i][j-1]];
    			if(delta>=tmp){
    				if(delta>tmp) tmp=delta, cur=best[i][j-1];
    				else if(best[i][j-1]<cur) cur=best[i][j-1];
    			}
    		}
    		best[i][j]=cur;
    	}
    int lastans=0,l,r;
    while(m--){
    	scanf("%d%d",&l,&r);
    	l=(l+lastans-1)%n+1;
    	r=(r+lastans-1)%n+1;
    	if(l>r) swap(l,r);
    	for(int i=l;i<=min(ed(belong[l]),r);++i) {
    		bucket[col[i]]+=1;
    		solve.push_back(col[i]);
    	}
    	if(belong[l] != belong[r]){
    		for(int i=st(belong[r]);i<=r;++i) {
    			bucket[col[i]]+=1;
    			solve.push_back(col[i]);
    		}
    	}
    	int tmp=0,cur=0;
    	int blockl=belong[l]+1, blockr=belong[r]-1;
    	if(blockl<=blockr){
    		cur=best[blockl][blockr], tmp=prefix[blockr][cur]-prefix[blockl-1][cur];
    		for(int i=0;i<solve.size();++i){
    			int delta=prefix[blockr][solve[i]]-prefix[blockl-1][solve[i]]+bucket[solve[i]];
    			if(delta>=tmp){
    				if(delta>tmp) tmp=delta,cur=solve[i];
    				else if(solve[i]<cur) cur=solve[i];
    			}
    		}
    	}
    	else{
    		for(int i=0;i<solve.size();++i){
    			int delta=bucket[solve[i]];
    			if(delta>=tmp){
    				if(delta>tmp) tmp=delta, cur=solve[i];
    				else if(solve[i]<cur) cur=solve[i];
    			}
    		}
    	}
    	for(int i=0;i<solve.size();++i) bucket[solve[i]]=0;
    	solve.clear();
    	lastans=A[cur];
    	printf("%d\n",lastans);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/9887060.html

时间: 2024-08-29 21:18:34

[Violet]蒲公英 分块的相关文章

[Luogu P4168] [Violet]蒲公英 (分块)

题面 洛咕 Solution 题目要求求出区间众数,强制在线. 区间众数是一个比较尴尬的问题,我们无法用区间数据结构来处理这个问题,因为我们没法很好的合并区间众数的答案. 既然区间数据结构解决不了这个问题,我们可以考虑一下使用基于分块的算法,例如莫队. 这题用莫队非常好处理,不幸的是,这题要求强制在线. 因此我们考虑使用分块算法. 分块算法的核心在于把一整个块的信息压缩起来以便快速处理. 我们要查询一段区间的众数,我们可以考虑这样搞:对于这个区间内连续的块,我们先快速地查询这个连续的块中的众数,

P4168 [Violet]蒲公英 分块

这道题算是好好写了.写了三种方法. 有一个好像是$qwq$$N\sqrt(N)$的方法,,但是恳请大佬们帮我看看为什么这么慢$qwq$(后面的第三种) 注:$pos[i]$表示$i$属于第$pos[i]$块. 第一种是统计所有可能的块组成的区间中(第i块到第j块),每个数出现的次数,记做$f[i][j][k]$,和所有可能的块组成的区间的答案,记做$h[i][j]$. 然后每次先把整块的答案作为初始答案,然后对于散块中的每个值$vl$,暴力修改对应的$f[i][j][vl]$,更新答案. 当块长

Luogu P4168 [Violet]蒲公英

P4168 [Violet]蒲公英 题意 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了.我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢.不过奶奶说他是很难受的时候才做出这样的事的-- 最近村子里长出了一大片一大片的蒲公英.一刮风,这些蒲公英就能飘到好远的地方了呢.我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢! 哥哥你要快点回来哦! 爱你的妹妹 \(V

【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 题解:分块还是练脑子啊~ 结论:一个区间的众数要么是区间中一个块的众数,要么是块外的任意

【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的众数位置.具体实现的话直接开个桶存一下就好了. 然后考虑询问,整块的直接拿出来求一下出现次

p4168 [Violet]蒲公英(分块)

区间众数的重题 和数列分块入门9双倍经验还是挺好的 然后开O2水过 好像有不带log的写法啊 之后在补就是咕咕咕 // luogu-judger-enable-o2 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <map> #include <cmath> using namespace std; int m,b

[日常摸鱼]bzoj2724蒲公英-分块

区间众数经典题~ http://begin.lydsy.com/JudgeOnline/problem.php?id=4839这里可以提交~ 题意大概就是没有修改的询问区间众数,如果有一样的输出最小的,强制在线,$n \leq 4*10^4,a_i \leq 10^9$. log数据结构脑补一遍好像没什么可以做的,数据范围我们可以分块! 不过分块之前肯定要离散化一下,而且还要保存离散化前的数据(因为要回答的是出现最多的数),离散化的方法在上一篇博客里面~ 假设分成$L$块,每块大小$s=\lfl

题解【luogu4168 [Violet]蒲公英】

Description 给出一个长度为 \(n\) 序列 \(a\) ,\(m\) 次询问,每次询问区间 \([l,r]\) 里的众数(出现次数最多的数).若有多个,输出最小的. \(a_i \leq 10^9, n \leq 40000, m \leq 50000\),强制在线. Solution \(a_i \leq 10^9\) ,先离散化.然后 算法一:暴力 \(n ^ 2\) ,预计得分 20 : 实际得分 20 (开了 O2 直接变成 85 啥操作) 算法二:\(n \leq 400

[Violet]蒲公英

题意: 给出一个长度为 \(n\) 序列\(a\) ,\(m\)次询问,每次询问区间 \(l,r\) 里的众数(出现次数最多的数).若有多个,输出最小的. \(a_i \leq 10^9, n \leq 40000, m \leq 50000\),强制在线. 题解: 看了题解才懂的.根据https://www.cnblogs.com/acfunction/p/10051345.html hzwer给出了更巧妙的方法http://hzwer.com/3582.html \(a_i \le 10^9