分块算法板子

https://www.luogu.org/problemnew/show/1903

用pre[i]数组记录上一次和当前i同色的位置

查询[l,r],若pre[i]<r,则说明在[l,i)区间内没用和i同色的,则++ans

于是就可以大胆地分块

对于每一块按照pre[i]排序,再进行二分了

复杂度O(qsqrt(n)log(n)).

#include<stdio.h>
#include<math.h>
#include<algorithm>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using std::sort;
using std::lower_bound;
const int N=10011;
const int M=1000011;
inline int min(int a,int b){
	return a<b?a:b;
}
int n,q,m,blo;
int c[N],pos[N],pre[N],b[N],last[M];
inline int find(int x,int v){
	int l=(x-1)*blo+1,r=min(x*blo,n);
	return lower_bound(pre+l,pre+r+1,v)-pre-l;
}
inline void reset(int x){
	int l=(x-1)*blo+1,r=min(x*blo,n);
	FOR(i,l,r)pre[i]=b[i];
	sort(pre+l,pre+r+1);
}
inline void build(){
	FOR(i,1,n){
		b[i]=last[c[i]];
		last[c[i]]=i;
		pos[i]=(i-1)/blo+1;
	}
	FOR(i,1,m)reset(i);
}
inline int ask(int l,int r){
	int ans=0;
	if(pos[l]==pos[r]){
		FOR(i,l,r)if(b[i]<l)++ans;
		return ans;
	}
	for(register int i=l;i<=blo*pos[l];++i)if(b[i]<l)++ans;
	for(register int i=blo*(pos[r]-1)+1;i<=r;++i)if(b[i]<l)++ans;
	for(register int i=pos[l]+1;i<pos[r];++i)ans+=find(i,l);
	return ans;
}
inline void change(int x,int v){
	FOR(i,1,n)last[c[i]]=0;
	c[x]=v;
	FOR(i,1,n){
		int t=b[i];
		b[i]=last[c[i]];
		if(t!=b[i])reset(pos[i]);
		last[c[i]]=i;
	}
}
int main(){
	scanf("%d%d",&n,&q);
	FOR(i,1,n)scanf("%d",c+i);
	blo=int(sqrt(n));
	m=n%blo?(n/blo+1):n/blo;
	build();
	char ch[5];int x,y;
	while(q--){
		scanf("%s%d%d",ch,&x,&y);
		if(ch[0]==‘Q‘)printf("%d\n",ask(x,y));
		else change(x,y);
	}
	return 0;
}

  

时间: 2024-10-16 09:45:54

分块算法板子的相关文章

c++分块算法(暴力数据结构)

快要noip了,该写些题解攒攒rp了(逃) 看到题解里那么多线段树啊,树状数组啊,本蒟蒻表示:这都是什么鬼东西? 在所有高级数据结构中,树状数组是码量最小的,跑的也基本是最快的,但理解很难,并且支持的操作很少:线段树的码量,相信写过线段树题的童鞋都亲身体验过这种恐怖(那些3min写完splay的巨佬不要d我),理解虽然简单,但一题调一辈子啊! 所以说到这里,本蒟蒻想表达什么呢? 分块大法吼啊! 有人会说:分块不是n√n的复杂度吗?怎么能跟nlogn的数据结构相提并论呢?或者说,分块在联赛中,有什

分块算法及模板

此文为博主原创,转载时请通知博主,并把原文链接放在正文醒目位置. 简要介绍 分块算法就是把一串数据分割成几块数据的算法,其实是对暴力的一种优化. 通常在分块时,每块的大小为√n.但最后一块的大小也可能小于√n,只能用暴力来算. 通过把对单个数据的操作转化为对几个块的数据的操作,能够节省时间,提高运算效率. 分块算法在处理大范围的修改.查询问题时有很大优势. 分块算法代码 1 /*此代码主要模仿了钟皓曦大佬的分块算法*/ 2 #include<iostream> 3 #include<cs

hdu 5057 Argestes and Sequence(分块算法)

Argestes and Sequence Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 566    Accepted Submission(s): 142 Problem Description Argestes has a lot of hobbies and likes solving query problems espec

【快速处理】分块算法

分块算法 ---------------------------------------------------------- 1.思想 如果我们需要对一个特定的序列进行操作,那么非常直观.简单的方法就是纯暴力(不,那叫模拟). 不过如果暴力能过的话,那就呵呵了. 所以我们要想一些比较高能的数据结构——分块. 相比线段树来说,分块算法比较难实现,但是只要深入理解,就可以实现了,只不过需要一些数据结构的辅助. 分块实质来说就是把一个序列切分,从而实现对查询.查找.替换等等操作的高效处理. ----

刷题总结——分块算法(bzoj2821作诗)

题目: Description 神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗.由于时间紧迫,SHY作完诗 之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一 些汉字构成诗.因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次.而且SHY认 为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!).于是SHY请LYD安排选 法.LYD这

分块算法

有一种很常见的题型  就是一个在一个好长的序列中进行 乍一看都是很麻烦的那种 修改和查询. 通常这种题 都是拿高端的数据结构 轻轻松松优化查询修改复杂度写过去,可是不会怎么办??! 于是就可以利用分块这种小技巧了. 这个技能就算是带奇技淫巧的暴力吧,暴力出奇迹. 简单来说 : 这种思路就是 把序列分成很多个块, 建立块与块之间的联系,然后每次修改就只需要改一个块里的东西. 如果分成 √N 块,每块有 √N 个 , 那么每次修改 查询 的操作 就都被减到了以前的根号级别, 所以就可以水过好多题 看

算法复习——分块算法

题目: 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 Vani原创 题解: 题解如上·····一个分块模板题打了我2个小时·····不得不说代码能力和专注度还不够···

分块算法总结

最近学了一些分块,来总结一下个人感受: 分块是什么呢?就是把一个大块拆成若干个小块进行计算,每个小块有可能有一些共同特点,或者每个小块内部是有顺序的,这样,在修改操作的时候,只需要算出两边的节点所属的小块的编号分别是什么,然后两边的散块(姑且这么叫)可以进行暴力修改,而中间的由于题目不同,可以进行不同的操作,比如说区间加,那么就可以在中间的每个小块上面直接像线段树一样打一个lazy标记,标记区间增加了多少.然后在查询的时候就可以直接对散块进行暴力查询,然后对整块运用之前设置的lazy标记,或者保

Z算法板子

给定一个串$s$, $Z$算法可以$O(n)$时间求出一个$z$数组 $z_i$表示$s[i...n]$与$s$的前缀匹配的最长长度, 下标从$0$开始 void init(char *s, int *z, int n) { int mx=0,l=0; REP(i,1,n-1) { z[i] = i<mx?min(mx-i,z[i-l]):0; while (s[z[i]]==s[i+z[i]]) ++z[i]; if (i+z[i]>mx) mx=i+z[i],l=i; } } 原文地址:h