P1903 带修莫队

[国家集训队] 数颜色 / 维护队列

题目描述

墨墨购买了一套 \(N\) 支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

  1. \(Q\ L\ R\) 代表询问你从第 \(L\) 支画笔到第 \(R\) 支画笔中共有几种不同颜色的画笔。

  2. \(R\ P\ Col\) 把第 \(P\) 支画笔替换为颜色 \(Col\)

为了满足墨墨的要求,你知道你需要干什么了吗?

输入格式

\(1\) 行两个整数 \(N\)\(M\),分别代表初始画笔的数量以及墨墨会做的事情的个数。

\(2\)\(N\) 个整数,分别代表初始画笔排中第 \(i\) 支画笔的颜色。

\(3\) 行到第 \(2+M\) 行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

4
4
3
4

提示

对于30%的数据,\(n,m \leq 10000\)

对于60%的数据,\(n,m \leq 50000\)

对于所有数据,\(n,m \leq 133333\)

所有的输入数据中出现的所有整数均大于等于 \(1\) 且不超过 \(10^6\)

增加了一维时间维

我们 q1 q2 分别保存 查询 修改

我们用cntq cntr 记录查询 修改

那么 q1[cntq].t=cntr q1[cntq].id=cntq

我们离线后处理 1~cntq时

L=1 R=0 T=0

L R与普通莫队一样

关于时间维度 类比 L R while T<q1[i].t T++ upd(i,T) while T>q1[i].t upd(i,T) T--

关于upd操作

inline void upd(int x,int t)
{
	if(q1[x].l<=q2[t].l&&q2[t].l<=q1[x].r)//如果修改的点(q2[t].l)在当前查询的区间内 就修改 
	{
		Delete(a[q2[t].l]);
		Add(q2[t].r);
		//.l存的修改点   .r存的修改值		
	}	
	swap(a[q2[t].l],q2[t].r);
}

我们q2[].l 记录的修改点 q2[].r 记录的修改值

最后swap是因为 我们双指针有Add Delete 而对于点修改 Delete等价于还原数据 所以 swap即可

关于 cmp

bool cmp(const md& x,const md& y)
{
	if(x.l/len!=y.l/len)return x.l/len<y.l/len;
	if(x.r/len!=y.r/len)return x.r/len<y.r/len;
	return x.t<y.t;
}

我们按照 l r 分别分了块 所以分别按块序数排序 最后块内按照时间升序排列

注意! sort(q1+1,q1+cntq+1,cmp) 不是 q1+m+1!!!

我们离线操作的始终是查询区间!!!

code

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,len,a[N],cnt[N],Ans=0,ans[N],cntq,cntc;
struct md {
	int l,r,t,id;
} q1[N],q2[N]; //q1:询问  q2:修改
inline void Add(int x) {
	cnt[x]++;
	Ans+=(cnt[x]==1);
}
inline void Delete(int x) {
	cnt[x]--;
	Ans-=(cnt[x]==0);
}
inline void upd(int x,int t) {
	if(q1[x].l<=q2[t].l&&q2[t].l<=q1[x].r) { //如果修改的点(q2[t].l)在当前查询的区间内 就修改
		Delete(a[q2[t].l]);
		Add(q2[t].r);
		//.l存的修改点   .r存的修改值
	}
	swap(a[q2[t].l],q2[t].r);
}
bool cmp(const md& x,const md& y) {
	if(x.l/len!=y.l/len)return x.l/len<y.l/len;
	if(x.r/len!=y.r/len)return x.r/len<y.r/len;
	return x.t<y.t;
}
signed main() {
	ios::sync_with_stdio(false);
	cin>>n>>m;
	len=pow(n,0.66667);//记住就行
	for(int i=1; i<=n; i++)cin>>a[i];
	for(int i=1; i<=m; i++) {
		char op;
		int l,r;
		cin>>op>>l>>r;
		if(op=='Q')cntq++,q1[cntq].l=l,q1[cntq].r=r,q1[cntq].t=cntc,q1[cntq].id=cntq;//t代表第几次修改
		else cntc++,q2[cntc].l=l,q2[cntc].r=r;
	}
	sort(q1+1,q1+cntq+1,cmp);
	int L=1,R=0,T=0;
	for(int i=1; i<=cntq; i++) {
		while(L>q1[i].l)L--,Add(a[L]);
		while(R<q1[i].r)R++,Add(a[R]);
		while(L<q1[i].l)Delete(a[L]),L++;
		while(R>q1[i].r)Delete(a[R]),R--;
		while(T<q1[i].t)T++,upd(i,T);//对当前查询区间有影响 修改
		while(T>q1[i].t)upd(i,T),T--;//对当前查询区间无影响 撤销修改操作
		ans[q1[i].id]=Ans;
	}
	for(int i=1; i<=cntq; i++)cout<<ans[i]<<"\n";
	return 0;
}
posted @ 2023-04-18 20:52  N0zoM1z0  阅读(4)  评论(0编辑  收藏  举报