BZOJ 2120: 数颜色/BZOJ 2453: 维护队列 带修改莫队

2120: 数颜色

Time Limit: 6 Sec  Memory Limit: 259 MB
Submit: 5428  Solved: 2165
[Submit][Status][Discuss]

Description

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

Input

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

Output

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

Sample Input

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

Sample Output

4
4
3
4

HINT

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。


这个题 解法多多

最开始想的是树状数组套主席树

还有PoPoQQQ大爷暴力水过

当然也有带修改莫队


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

typedef long long ll;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<48||ch>57){if(ch=='-')f=-1;ch=getchar();}
	while(ch<=57&&ch>=48){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+48);}

const int N=10100,M=1000100;

int bel[N],n,Q,sz,cnt;

struct question{int l,r,time,id;}q[N];

inline bool cmp( question x, question y)
{return bel[x.l]==bel[y.l]?x.r<y.r:bel[x.l]<bel[y.l];}

struct change_clr{int pos,clr,pre;}w[N];

int clr[N],last[N],ans[N],num[M],res;

bool vis[N];

inline void cal(int x)
{
	if(vis[x])if(!(--num[clr[x]]))res--;
	if(!vis[x])if((++num[clr[x]])==1)res++;
	vis[x]^=1;
}

inline void modify(int k,int val)
{if(vis[k]){cal(k);clr[k]=val;cal(k);}else clr[k]=val;}

void solve()
{
	register int l=1,r=1,i,j;cal(1);
	for(i=1;i<=sz;++i)
	{
		for(j=q[i-1].time+1;j<=q[i].time;++j)modify(w[j].pos,w[j].clr);
		for(j=q[i-1].time;j>q[i].time;j--)modify(w[j].pos,w[j].pre);
		while(r<q[i].r)cal(++r);
		while(r>q[i].r)cal(r--);
		while(l>q[i].l)cal(--l);
		while(l<q[i].l)cal(l++);
		ans[q[i].id]=res;
	}
}

int main()
{
	n=read();Q=read();
	register int i,x,y,block;char ch[10];
	for(i=1;i<=n;++i)clr[i]=read(),last[i]=clr[i];
	for(i=1;i<=Q;++i)
	{
		scanf("%s",ch);x=read();y=read();
		if(ch[0]=='R'){w[++cnt].pos=x;w[cnt].clr=y;w[cnt].pre=last[x];last[x]=y;}
		else {q[++sz].l=x;q[sz].r=y;q[sz].id=sz;q[sz].time=cnt;}
	}
	block=sqrt(n);
	for(i=1;i<=n;++i)bel[i]=(i-1)/block+1;
	sort(q+1,q+sz+1,cmp);
	solve();
	for(i=1;i<=sz;++i)print(ans[i]),puts("");
	return 0;
} 
/*
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

4
4
3
4
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值