『带修改莫队』数颜色

题目描述

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。

墨墨会像你发布如下指令:

  • 1 1 1 Q Q Q L L L R R R代表询问你从第 L L L支画笔到第 R R R支画笔中共有几种不同颜色的画笔。
  • 2 2 2 R R R P P P C o l Col Col 把第 P P P支画笔替换为颜色 C o l Col Col。为了满足墨墨的要求,你知道你需要干什么了吗?

题解

如果没有修改操作,就是莫队的板子题。

带上操作以后,我们只要在原始的莫队上面加上一维时间;在每一次转移的时候,区间转移完以后再转移第三维时间。至于具体的转移方法,我们就再维护一个时间的指针即可;对新修改的数和原序列的数进行交换:注意不能直接复制,因为会出现从时间减少的情况。

细节:

  • 块为 n 1 3 n^{\frac{1}{3}} n31,总时间复杂度是: O ( n 3 5 ) . O(n^{\frac{3}{5}}). O(n53).
  • 初始化 l = 1 , r = 0 , t = 0. l=1,r=0,t=0. l=1,r=0,t=0.具体为什么我也不知道

代码如下:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

int n,m,T;
int t1 = 0;
int t2 = 0;
int ans = 0;
int a[2000000];
int Ans[2000000];
int cnt[2000000];
struct ques 
{
	int L,R,id,t;
	int p;
	friend bool operator < (ques p1, ques p2) 
	{
		if (p1.p ^ p2.p) return p1.p < p2.p;
		if (p1.R ^ p2.R) return p1.R < p2.R;
		return p1.t < p2.t;
 	}
} q[2000000];
struct node {
	int pos,val;
} c[2000000];

inline int read(void)
{
	int s = 0, w = 1;char c = getchar();
	while (c<'0' || c>'9') {if (c == '-') w = -1; c = getchar();}
	while (c>='0' && c<='9') s = s*10+c-48,c = getchar();
	return s*w;
}

void ins(int x)
{
	cnt[a[x]] ++;
	if (cnt[a[x]] == 1) ans ++;
	return;
}

void del(int x)
{
	cnt[a[x]] --;
	if (cnt[a[x]] == 0) ans --;
	return;
}

void Change(int t,int l,int r)
{
	if (c[t].pos >= l && c[t].pos <= r)
	{
		cnt[a[c[t].pos]] --;
		if (cnt[a[c[t].pos]] == 0) ans --;
		cnt[c[t].val] ++;
		if (cnt[c[t].val] == 1) ans ++;
	}
	swap(a[c[t].pos],c[t].val);
	return;
}

int main(void)
{
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	n = read();
	m = read();
	T = pow(n, 2.0 / 3.0);
	for (int i=1;i<=n;++i) a[i] = read();
	for (int i=1;i<=m;++i) 
	{
		char ch = getchar();
		while (ch ^ 'Q' && ch ^ 'R') ch = getchar();
		if (ch == 'Q') q[++t1] = ques{read(), read(), t1, t2};
		if (ch == 'R') c[++t2] = node{read(), read()};
		if (ch == 'Q') q[t1].p = (q[t1].L + T -1) / T;
	}
	sort(q+1, q+t1+1);
	int l = 1;
	int r = 0;
	int t = 0;
	ans = 0;
	for (int i=1;i<=t1;++i)
	{
		while (l > q[i].L) ins(--l);
		while (r < q[i].R) ins(++r);
		while (l < q[i].L) del(l++);
		while (r > q[i].R) del(r--);
		while (t < q[i].t) Change(++t,q[i].L,q[i].R);
		while (t > q[i].t) Change(t--,q[i].L,q[i].R);
		Ans[q[i].id] = ans;
	}
	for (int i=1;i<=t1;++i) printf("%d\n", Ans[i]);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值