BZOJ 2120: 数颜色 && 2453: 维护队列 【带修莫队版题【也可以学黄学长分块

80 篇文章 0 订阅
2 篇文章 0 订阅

……学莫队QwQ    好神啊QwQ

复杂度什么的xjb讨论一下感觉好像挺对的23333

加个修改就相当于变成三维的查询……直接用三个指针,维护当前记录的左端点右端点和时间,

先把询问按照

    第一关键字:左端点所在的块

    第二关键字:右端点所在的块

    第三关键字:前一个修改操作的时间

排序,然后xjb暴力做,yy一下可以证明……块大小是N^(2/3)的时候最优  于是就这么写咯……和普通莫队……没啥区别?

#include<cmath>
#include<cstdio>
#include<cctype>
#include<algorithm>
#define MAXN 10005
using namespace std;	int n,m;
inline int read(){
	register int ch = getchar();
	while(!isdigit(ch))	ch = getchar();
	register int rtn = 0 ;
	while(isdigit(ch))	rtn = rtn*10 + ch - '0' , ch = getchar() ;
	return rtn;
}

int a[MAXN] ;
int col[MAXN] ;
int yjq[MAXN] , laekov ;

struct ASK{
	int id,l,r,pre;
	ASK(){}
	ASK(int id,int l,int r,int pre):
		id(id),l(l),r(r),pre(pre){}
	bool operator < (const ASK ano) const {
		if(yjq[l]==yjq[ano.l])
			return yjq[r]==yjq[ano.r] ?
				pre < ano.pre :
				yjq[r] < yjq[ano.r] ;
		else
			return yjq[l] < yjq[ano.l] ;
	}
}ask[MAXN];	int cnt_ask;
int ans[MAXN];

struct MODIFY{
	int id,pos,v,pre;
	MODIFY(){}
	MODIFY(int id,int pos,int v,int pre):
		id(id),pos(pos),v(v),pre(pre){}
}mdf[MAXN];	int cnt_mdf;

int tot = 0 ;
int cnt[1000006] ;
inline void add(int x) {tot += (++cnt[x])==1 ;}
inline void del(int x) {tot -= !(--cnt[x]) ;}

inline void work(){
	for(int i=1;i<=n;++i)	col[i] = a[i] ;
	int L=1,R=1,TIME=0;
	add(col[L]);
	for(int i=1;i<=cnt_ask;++i){
		int l = ask[i].l , r = ask[i].r , tim = ask[i].pre ;
		while(TIME<tim){
			++TIME;
			int pos = mdf[TIME].pos;
			col[pos] = mdf[TIME].v;
			if(pos>=L&&pos<=R)
				del(mdf[TIME].pre) , add(mdf[TIME].v);
		}
		while(TIME>tim){
			col[mdf[TIME].pos] = mdf[TIME].pre;
			int pos = mdf[TIME].pos;
			if(pos>=L&&pos<=R)
				del(mdf[TIME].v) , add(mdf[TIME].pre);
			--TIME;
		}
		while(L<l)	del(col[L++]);
		while(L>l)	add(col[--L]);
		while(R<r)	add(col[++R]);
		while(R>r)	del(col[R--]);
		ans[ask[i].id] = tot ;
	}
}

char opt[5];
int now_pre = 0 ;
int read_x,read_y;
int main(){
	freopen("1.in","r",stdin);
	n = read() , m = read() ;
	laekov = pow(n,2.0/3.0);
	for(int i=1;i<=n;++i)	a[i] = col[i] = read() ;
	for(int i=1;i<=m;++i){
		scanf("%s",opt) , read_x = read() , read_y = read();
		if(opt[0]=='Q')
			ask[++cnt_ask] = ASK(cnt_ask,read_x,read_y,now_pre);
		else{
			mdf[++cnt_mdf] = MODIFY(cnt_mdf,read_x,read_y,col[read_x]);
			col[read_x] = read_y ;
			now_pre = cnt_mdf ;
		}
	}

	sort(ask+1,ask+cnt_ask+1);

	work();

	for(int i=1;i<=cnt_ask;++i)
		printf("%d\n",ans[i]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值