2521. 数颜色

题目链接

2521. 数颜色

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

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

  1. Q L R 代表询问你从第 L 支画笔到第 R 支画笔中共有几种不同颜色的画笔。
  2. R P Col 把第 P 支画笔替换为颜色 Col

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

输入格式

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

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

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

输出格式

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

数据范围

1N,M10000,
修改操作不多于 1000 次,
所有的输入数据中出现的所有整数均大于等于 1 且不超过 106

输入样例:

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×len),块间距离为 O(len)l 指针块间移动最多 O(n/len) 次,块间复杂度为 O(len×n/len),故其复杂度为 O(m×len+n)O(m×len)r 指针也同样考虑,块内复杂度为 O(m×len)r 指针每个块块间移动的距离为 O(n),共 n/len 块,故块间复杂度为 O(n2/len),故其复杂度为 O(m×len+n2/len),设每次 t 指针移动的最长距离为 t,由于 t 指针在 lr 指针固定在某一块时其复杂度为 O(t)lr 指针形成的块共有 O(n/len×n/len) 块,故其复杂度为 O(t×n2/len2),由于 nm 一个规模,故复杂度替换如下:

l:O(n×len)r:O(n×len+n2/len)t:O(t×n2/len2)

对于 r 指针,设 n×len>n2/len,即 len>n,而对于 t 指针,要求 len 越大越好,故 len>n 成立,则 r 指针的复杂度也为 O(n×len),令 n×len=t×n2/len2,得 len=3nt,则:

  • 时间复杂度:O(3n4t)

代码

// 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; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16767440.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-10-07 2020 CCPC Wannafly Winter Camp Day6 Div.1&2
点击右上角即可分享
微信分享提示