洛谷 P1903 BZOJ 2120 清橙 A1274【模板】分块/带修改莫队(数颜色)(周奕超)
试题来源
题目描述
墨墨购买了一套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支画笔中共有几种不同颜色的画笔。
输入输出样例
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
说明
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
来源:bzoj2120
本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。
吐槽
这题A得不容易啊!从前一天晚上开始敲,但是第一次敲,对于原理理解不足,许多细节出了实现偏差差错,交到洛谷上,洛谷自造数据特性太平均全部爆零,洛谷还不提供数据,不得已搬到其他OJ上交,BZOJ不用说了,结果就一个WA,codevs没收这题,COGS(提供许多数据下载)交上去找不到输出文件,最后终于找到了清橙,虽然也不提供数据下载,但清橙的数据分布合理啊——
不像其他OJ,没有达到我查错的目的。我在清橙上交了一堆60,于是把差错范围锁定到了颜色更换的部分,长乐一中集训DAY3一整天挤出时间,一点点改错(前一天晚上写的简直是混乱不堪啊),终于在去华莱士吃完晚饭回来后AC了这题华莱士吼啊。
——————————————————2019年3月23日11:21:28更新————————————————
重新学习
2019年3月25日00:31:58 洛谷上的数据范围变成五倍了
解题思路
待修改的莫队只需要在四个更改区间左右端点的四重循环前加上两重更新颜色的循环即可。
另外极其重要的一点是注意莫队的初始化,初始左右端点之间的颜色要先统计了。一定要注意如果要修改的颜色不在统计范围内,那么改颜色即可,不必改颜色种数(事后说起来好简单啊,调的时候就是改不出来)
源代码
#include<math.h> #include<cstdio> #include<cstring> #include<algorithm> int n,m; int color[10010]={0}; int last [10010]={0}; int f[1000010]={0};//离散化后颜色统计 bool vis[10010]={0}; struct query{ int id,l,pos,r; int t;//上一个修改的change_cnt int ans; }an[10010]; int query_cnt=0; int aa[10010]={0}; int cmp(const query & a,const query& b) { if(a.pos==b.pos) { if(a.r==b.r) return a.t<b.t; return a.r<b.r; } return a.pos<b.pos; } void add(int & sum,int pos) { f[color[pos]]++; if(f[color[pos]]==1) sum++; vis[pos]=1; } void del(int & sum,int pos) { f[color[pos]]--; if(!f[color[pos]]) sum--; vis[pos]=0; } struct Change{ int t,pos,qian,hou; }ch[10010]; int change_cnt=0; int main() { //freopen("nt2011_color1.in","r",stdin);//在cogs上提交的记号 //freopen("nt2011_color1.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&color[i]); last[i]=color[i]; } for(int i=1,x,y,kuai=pow(n,2.0/3.0);i<=m;i++) { char c; scanf("\n%c %d %d",&c,&x,&y); if(c=='Q') query_cnt++,an[query_cnt]={query_cnt,x,x/kuai,y,change_cnt,0}; else change_cnt++,ch[change_cnt]={change_cnt,x,last[x],y},last[x]=y; } std::sort(an+1,an+query_cnt+1,cmp); f[color[1]]++;vis[1]=1; for(int i=1,l=1,r=1,sum=1;i<=query_cnt;i++) { for(int j=an[i-1].t+1;j<=an[i].t;j++) { if(vis[ch[j].pos]) { del(sum,ch[j].pos); color[ch[j].pos]=ch[j].hou; add(sum,ch[j].pos); } else color[ch[j].pos]=ch[j].hou; } for(int j=an[i-1].t;j>an[i].t;j--) { if(vis[ch[j].pos]) { del(sum,ch[j].pos); color[ch[j].pos]=ch[j].qian; add(sum,ch[j].pos); } else color[ch[j].pos]=ch[j].qian; } while(r<an[i].r) r++,add(sum,r); while(l<an[i].l) del(sum,l),l++; while(r>an[i].r) del(sum,r),r--; while(l>an[i].l) l--,add(sum,l); an[i].ans=sum; } for(int i=1;i<=query_cnt;i++) aa[an[i].id]=an[i].ans; for(int i=1;i<=query_cnt;i++) printf("%d\n",aa[i]); return 0; }