码迷,mamicode.com
首页 > 编程语言 > 详细

分块算法板子

时间:2017-11-26 23:00:00      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:说明   last   www   print   查询   define   int   记录   math   

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;
}

  

分块算法板子

标签:说明   last   www   print   查询   define   int   记录   math   

原文地址:http://www.cnblogs.com/Stump/p/7900591.html

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