【模板】带修改莫队 (模板题:洛谷P1903数颜色)
2017-05-25 18:38
260 查看
带修改莫队讲解
~阅前提示:拥有普通莫队的基础知识;理解莫队的思想;
~简介:
莫队支持的是离线操作,普通莫队只支持查询操作;
而带修改莫队还支持单点修改操作。
~原理:
普通莫队每一个询问有L,R,ID三个属性;因为只有查询操作,所以改变其查询顺序并不会影响算法的正确性;而加入单点修改后,就不能任意改变顺序,这会影响最终答案;带修改莫队的思路就是在查询中加一个属性TM,表示在原顺序中该查询之前离其最近的一个修改操作的ID;每次执行查询操作前都执行在它之前的修改,并将在它之后的修改操作中已执行的取消;这样就可以不改变原始的顺序了。~实现
在存储修改操作时,使用前向星思想:PRE,COLOR,POS,分别表示前一个修改操作、该修改操作修改的颜色、操作的数;那遍历时只需依次向前即可;在下面的程序中将会看见
for (int j=e[i-1].tm+1;j<=e[i].tm;++j)即可实现从上一个操作中可能没有被操作过的修改
for (int j=e[i-1].tm;j>=e[i].tm+1;--j)即可实现从上一个操作中可能执行过的多余的修改
题目描述
墨墨购买了一套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: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
说明
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> using namespace std; int CL=1,CR=0,ans=0,tim,n,m,k,cnt=0,sz=0; int color[50010],num[1000010];//num存该颜色出现的次数 int las[50010],answer[200010]; //las存x个数的前一个颜色,具体操作类似于前向星 bool vis[50010];// struct XY{ //存sz个询问 int L,R,id,tm; }e[200010]; struct XX{ //存cnt个修改 int ps,cl,pre; }w[200010]; bool cmp(XY a,XY b){ //莫队的排序(不清楚的可以先做莫队的模板) return (a.L/tim)==(b.L/tim)? a.R<b.R : a.L<b.L; }; void cala(int x){ //相当于莫队的Inc和dec if (vis[x]){ if ((--num[color[x]])==0) --ans; //如果此次减掉的是最后一个,则颜色数-1 }else{ if ((++num[color[x]])==1) ++ans; //如果是新增的数,则颜色数+1 } vis[x]=!vis[x]; //vis可以理解为一个标识符 //(即是否会影响或在上一次查询中) //而更新过答案后应将其重置(取反) //设定为取反则在change操作中便于实现 } void change(int x,int c){ //将第x个改成颜色c if (vis[x]){ cala(x);color[x]=c;cala(x); //假如存在x的修改可能影响正确性,则在修改 //颜色前后都应更新答案,而两个cala则不会改变当前指针 }else color[x]=c; } int main(){ char cha;int x,y; cin >>n>>m;tim=sqrt(n);//tim是莫队的核心了吧 for (int i=1;i<=n;++i) scanf("%d",&color[i]),las[i]=color[i];//初始颜色 for (int i=1;i<=m;++i){ cin >>cha;scanf("%d%d",&x,&y); if (cha=='R'){ ++cnt;w[cnt].ps=x;w[cnt].cl=y;w[cnt].pre=las[x];las[x]=y; //前向星式存修改 }else{ ++sz;e[sz].L=x;e[sz].R=y;e[sz].id=sz;e[sz].tm=cnt; //存询问时要加上最近一次修改的ID(tm),便于后面操作 } } sort(e+1,e+1+sz,cmp); for (int i=1;i<=sz;++i){ for (int j=e[i-1].tm+1;j<=e[i].tm;++j) change(w[j].ps,w[j].cl); //将所有未修改的点修改 for (int j=e[i-1].tm;j>=e[i].tm+1;--j) change(w[j].ps,w[j].pre);//将所有已修改的点还原 //(上次操作多余的修改) int l=e[i].L,r=e[i].R; //下面就是普通莫队了 while (CL<l) cala(CL++); while (CL>l) cala(--CL); while (CR<r) cala(++CR); while (CR>r) cala(CR--); answer[e[i].id]=ans; } for (int i=1;i<=sz;++i) printf("%d\n",answer[i]); return 0; }
相关文章推荐
- bzoj 2120 数颜色 【带修改莫队模板】
- 洛谷 P1903 [国家集训队]数颜色 带修改的莫队算法
- [国家集训队]数颜色 洛谷 1903 带修改的莫队
- COGS.1901.[模板][国家集训队2011]数颜色(带修改莫队)
- [BZOJ]2120 数颜色 带修改莫队
- HYSBZ - 2120:数颜色 (带修改操作的莫队算法)
- [BZOJ2120]数颜色(带修改莫队入门)
- Dynamic len 题解+代码 (带修改莫队算法模板)
- [BZOJ2120]数颜色(带修改莫队)
- [BZOJ2120][带修改莫队算法]数颜色
- BZOJ2120数颜色(带修改莫队)
- BZOJ2120 数颜色 【带修改莫队】
- 【JZOJ 4594】 Dynamic len &【JZOJ 2491】维护队列(带修改的莫队算法 模板)
- [JZOJ4594] [UVa12345] Dynamic len(带修改莫队算法模板)
- bzoj 2120 数颜色 带修改莫队
- luoguP1903 数颜色(通过一道题认识带修改莫队)
- BZOJ.2453.维护队列([模板]带修改莫队)
- 修改dedecms 5.6 模板默认颜色样式技巧
- 如何修改dede模板的默认颜色
- bzoj 2120 数颜色 待修改的莫队