2521. 数颜色

题目链接

2521. 数颜色

墨墨购买了一套 \(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 \le N,M \le 10000\),
修改操作不多于 \(1000\) 次,
所有的输入数据中出现的所有整数均大于等于 \(1\) 且不超过 \(10^6\)

输入样例:

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

解题思路

带修改的莫队

莫队算法是暴力离线算法,一般不支持修改操作,如果需要修改操作,则需要在原基础上增加一个维度,即 \((l,r,t)\),将区间分块,设其长度为 \(len\),则每一个时间戳有 \(n/len\) 块长度为 \(len\) 的块,同理每次先将 \(l,r\) 两个指针移到询问端点上,再将 \(t\) 指针暴力移到对应时间戳即可
复杂度分析:分别考虑三个指针的总时间复杂度,\(l\) 指针分为块内和块间的复杂度,块内复杂度为 \(O(m\times len)\),块间距离为 \(O(len)\)\(l\) 指针块间移动最多 \(O(n/len)\) 次,块间复杂度为 \(O(len\times n/len)\),故其复杂度为 \(O(m\times len+n)\approx O(m\times len)\)\(r\) 指针也同样考虑,块内复杂度为 \(O(m\times len)\)\(r\) 指针每个块块间移动的距离为 \(O(n)\),共 \(n/len\) 块,故块间复杂度为 \(O(n^2/len)\),故其复杂度为 \(O(m\times len+n^2/len)\),设每次 \(t\) 指针移动的最长距离为 \(t\),由于 \(t\) 指针在 \(l\)\(r\) 指针固定在某一块时其复杂度为 \(O(t)\)\(l\)\(r\) 指针形成的块共有 \(O(n/len\times n/len)\) 块,故其复杂度为 \(O(t\times n^2/len^2)\),由于 \(n\)\(m\) 一个规模,故复杂度替换如下:

\[l:O(n\times len)\\ r:O(n\times len+n^2/len)\\ t:O(t\times n^2/len^2) \]

对于 \(r\) 指针,设 \(n\times len>n^2/len\),即 \(len>\sqrt{n}\),而对于 \(t\) 指针,要求 \(len\) 越大越好,故 \(len>\sqrt{n}\) 成立,则 \(r\) 指针的复杂度也为 \(O(n\times len)\),令 \(n\times len=t\times n^2/len^2\),得 \(len=^3\sqrt{nt}\),则:

  • 时间复杂度:\(O(^3\sqrt{n^4t})\)

代码

// Problem: 数颜色
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2523/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=10005,M=1e6+5;
int n,m,cnt[M],mc,mq,w[N],len,ans[N];
struct query
{
	int id,l,r,t;
}q[N];
struct modify
{
	int p,v;
}c[N];
int get(int x)
{
	return x/len;
}
void add(int x,int &res)
{
	if(!cnt[x])res++;
	cnt[x]++;
}
void del(int x,int &res)
{
	cnt[x]--;
	if(!cnt[x])res--;
}
bool cmp(const query& a, const query& b)
{
    int al = get(a.l), ar = get(a.r);
    int bl = get(b.l), br = get(b.r);
    if (al != bl) return al < bl;
    if (ar != br) return ar < br;
    return a.t < b.t;
}
int main()
{
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<=m;i++)
    {
    	char op[2];
    	int l,r;
    	scanf("%s%d%d",op,&l,&r);
    	if(*op=='Q')++mq,q[mq]={mq,l,r,mc};
    	else
    		mc++,c[mc]={l,r};
    }
    len=cbrt((double)n*max(mc,1))+1;
    sort(q+1,q+1+mq,[](const query &a,const query &b){
    	int al=get(a.l),ar=get(a.r),bl=get(b.l),br=get(b.r);
    	if(al!=bl)return al<bl;
    	if(ar!=br)return ar<br;
    	return a.t<b.t;
    });
    for(int i=0,j=1,t=0,res=0,k=1;k<=mq;k++)
    {
    	int l=q[k].l,r=q[k].r,tm=q[k].t,id=q[k].id;
    	while(i<r)add(w[++i],res);
    	while(i>r)del(w[i--],res);
    	while(j<l)del(w[j++],res);
    	while(j>l)add(w[--j],res);
    	while(t<tm)
    	{
    		t++;
    		if(j<=c[t].p&&c[t].p<=i)
    		{
    			del(w[c[t].p],res);
    			add(c[t].v,res);
    		}
    		swap(w[c[t].p],c[t].v);
    	}
    	while(t>tm)
    	{
    		if(j<=c[t].p&&c[t].p<=i)
    		{
    			del(w[c[t].p],res);
    			add(c[t].v,res);
    		}
    		swap(w[c[t].p],c[t].v);
    		t--;
    	}
    	ans[id]=res;
    }
    for(int i=1;i<=mq;i++)printf("%d\n",ans[i]);
    return 0;
}
posted @ 2022-10-07 22:49  zyy2001  阅读(23)  评论(0编辑  收藏  举报