题解 洛谷P1903/BZOJ2120【[国家集训队]数颜色 / 维护队列】
对于不会树套树、主席树的本蒟蒻,还是老老实实的用莫队做吧....
其实这题跟普通莫队差不了多远,无非就是有了一个时间,当我们按正常流程排完序后,按照基本的莫队来,做莫队时每次循环对于这一次操作,我们在结构体中记录一下这次操作前有多少个改值操作,然后将当前的ans和每个点的颜色信息更新至当前队列(此队列不是莫队,是原队列)的状态再移动l,r两指针。
简单点说:
设当前询问为a,下一个询问为b,我们已知a,要求b。
首先我们像普通莫队一样转移左右端点。
这时候我们可能会发现a和b的经历的修改次数不同!
假如a较b少修改了p次,那我们就把这p次修改一个一个从前往后暴力地加上去。假如a较b多修改了q次,那我们就把这q次修改从后往前还原掉。
还要注意一点:
带修改的莫队的询问排序方法为:
- 第一关键字:左端点所在块编号,从小到大排序。
- 第二关键字:右端点所在块编号,从小到大排序。
- 第三关键字:经历的修改次数。也可以说是询问的先后,先询问的排前面。
注意的几点:
- 时间上的优化:将块的大小从sqrt(n)改为n的二分之三次方
- 可修改莫队只用于单点修改,区间修改的题目就算了吧...
- 复杂度大约为O(n的五分之三次方)
- 一样是离线操作
但是具体怎么操作呢?
我们先看一下结构体:
struct Node{
int l,r,c,id;
bool operator < (const Node a)const {
if(l/Be==a.l/Be){
if(r/Be==a.r/Be)return id<a.id;
return r<a.r;
}return l<a.l;
}
}q[N];
上面的重载运算符就是按照上文的排序方式来写的。
结构体中l,r分别是询问的左右端点,c是该询问之前的修改操作次数,id是这个操作的位置。
再来比较一下普通的莫队操作和可修改的莫队操作:
更新ans的函数(一样的):
inline void Add(int x){if(!sum[x])ans++;sum[x]++;}
inline void Del(int x){sum[x]--;if(!sum[x])ans--;}
普通莫队:
for(register int i=1;i<=m;++i){
while(l>q[i].l)l--,Add(val[l]);
while(r<q[i].r)r++,Add(val[r]);
while(l<q[i].l)Add(val[l]),l++;
while(r>q[i].r)Add(val[r]);,r--;
Ans[q[i].id]=ans;
}
可修改莫队:
for(register int i=0;i<c1;++i){
for(;lst<q[i].c;lst++){
if(l<=Q[lst][0]&&Q[lst][0]<=r)
Del(Q[lst][1]),Add(Q[lst][2]);
val[Q[lst][0]]=Q[lst][2];
}
for(;lst>q[i].c;lst--){
if(l<=Q[lst-1][0]&&Q[lst-1][0]<=r)
Del(Q[lst-1][2]),Add(Q[lst-1][1]);
val[Q[lst-1][0]]=Q[lst-1][1];
}
for(++r;r<=q[i].r;r++)Add(val[r]);
for(--r;r>q[i].r;r--)Del(val[r]);
for(--l;l>=q[i].l;l--)Add(val[l]);
for(++l;l<q[i].l;l++)Del(val[l]);
Ans[q[i].id]=ans;
}
(注:可修改莫队的下面四个for循环,是在我的心态极不好的时候才从让我WA了几遍的while循环改过来的,但是后面才发现不是while的原因......贴代码过来时不想改了)
我们发现,可修改莫队多了一段:
for(;lst<q[i].c;lst++){
if(l<=Q[lst][0]&&Q[lst][0]<=r)
Del(Q[lst][1]),Add(Q[lst][2]);
val[Q[lst][0]]=Q[lst][2];
}
for(;lst>q[i].c;lst--){
if(l<=Q[lst-1][0]&&Q[lst-1][0]<=r)
Del(Q[lst-1][2]),Add(Q[lst-1][1]);
val[Q[lst-1][0]]=Q[lst-1][1];
}
没错!这就是这段话:
假如a较b少修改了p次,那我们就把这p次修改一个一个从前往后暴力地加上去。假如a较b多修改了q次,那我们就把这q次修改从后往前还原掉。
上面的if是来判断这个改色操作是否在当前莫队范围中,在的话肯定要维护一下当前的莫队ans值嘛,但是不在范围中的话,直接改颜色不就好了......(貌似并没有那么难操作诶)
输入时的操作:
用一个变量c1表示有多少个询问操作,c2表示有多少个更改操作。
- 用结构体保存每次询问操作的相关信息
- 用一个二维数组保存每次更改操作的相关信息
代码:
for(int i=1,a,b;i<=m;i++)
if(scanf("%s",opt),read(a),read(b),opt[0]=='Q')
q[c1].l=a,q[c1].r=b,q[c1].id=c1,q[c1].c=c2,c1++;
else Q[c2][0]=a,Q[c2][1]=C[a],Q[c2][2]=C[a]=b,c2++;
- Q[i][0] 表示第i次操作需更改的位置
- Q[i][1] 表示第i次操作更改位置的现在颜色
- Q[i][2] 表示第i次操作要改成的颜色
- 注意,Q[i][1]在之前的更改操作中可能已经被改过,而我们有要记录这个点现在的值,所以我维护了一个C数组来随时记录每次操作的变化,原序列数组为val数组,显然是不能用原序列数组来记录的(不然到莫队时就乱了)
说了这么多,总算是要贴AC代码了。
AC代码(请原谅我鬼畜的码风,压行压疯了...):
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define A printf("A")
#define P(x) printf("V %d V",x);
#define S 1000003
using namespace std;
const int N=5e4+5;
template<typename _Tp>inline void read(_Tp&dig){
char c;dig=0;
while(c=getchar(),!isdigit(c));
while(isdigit(c))dig=dig*10+c-'0',c=getchar();
}
int n,m,Be,c1,c2,ans,C[N],val[N],Ans[N],sum[S],Q[N][3];
struct Node{
int l,r,c,id;
bool operator < (const Node a)const {
if(l/Be==a.l/Be){
if(r/Be==a.r/Be)return id<a.id;
return r<a.r;
}return l<a.l;
}
}q[N];char opt[10];
inline void Add(int x){if(!sum[x])ans++;sum[x]++;}
inline void Del(int x){sum[x]--;if(!sum[x])ans--;}
int main(){
read(n);read(m);Be=pow(n,(double)2/(double)3);
for(register int i=1;i<=n;++i)read(val[i]),C[i]=val[i];
for(int i=1,a,b;i<=m;i++)
if(scanf("%s",opt),read(a),read(b),opt[0]=='Q')
q[c1].l=a,q[c1].r=b,q[c1].id=c1,q[c1].c=c2,c1++;
else Q[c2][0]=a,Q[c2][1]=C[a],Q[c2][2]=C[a]=b,c2++;
sort(q,q+c1),Add(val[1]);int l=1,r=1,lst=0;
for(register int i=0;i<c1;++i){
for(;lst<q[i].c;lst++){
if(l<=Q[lst][0]&&Q[lst][0]<=r)
Del(Q[lst][1]),Add(Q[lst][2]);
val[Q[lst][0]]=Q[lst][2];
}
for(;lst>q[i].c;lst--){
if(l<=Q[lst-1][0]&&Q[lst-1][0]<=r)
Del(Q[lst-1][2]),Add(Q[lst-1][1]);
val[Q[lst-1][0]]=Q[lst-1][1];
}
for(++r;r<=q[i].r;r++)Add(val[r]);
for(--r;r>q[i].r;r--)Del(val[r]);
for(--l;l>=q[i].l;l--)Add(val[l]);
for(++l;l<q[i].l;l++)Del(val[l]);
Ans[q[i].id]=ans;
}for(register int i=0;i<c1;++i)printf("%d\n",Ans[i]);
return 0;
}
提交上去,哇,~跑的真快~慢死了!(好吧,我觉的还需优化一下......)
** 参考隔壁机房 叉ZY 大佬的文章,在此鸣谢叉ZY大佬
~我居然因为少了个等于号调了一个多小时.....~
题解 洛谷P1903/BZOJ2120【[国家集训队]数颜色 / 维护队列】的更多相关文章
- bzoj2120 / P1903 [国家集训队]数颜色 / 维护队列(带修改莫队)
P1903 [国家集训队]数颜色 / 维护队列 带修改的莫队 在原有指针$(l,r)$上又添加了时间指针$t$ 贴一段dalao的解释 带修改的莫队,和原版莫队相比,多了一个时间轴 原版莫队是将区间( ...
- P1903 [国家集训队]数颜色 / 维护队列(莫队区间询问+单点修改)
题目链接:https://www.luogu.org/problemnew/show/P1903 题目大意:中文题目 具体思路:莫队单点修改+区间询问模板题,在原来的区间询问的基础上,我们要记录当前这 ...
- 洛谷 P1903 [国家集训队]数颜色 / 维护队列
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. \(Q\) \(L\) \(R\) 代表询问你从第L支画笔到第R支画笔中共有几种不同 ...
- 洛谷P1903 [国家集训队]数颜色 / 维护队列 ( 带 修 )
题意:有两种操作: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 对每个1操作 输出答案: 带修莫队 模板题 (加 ...
- 洛谷 P1903 [国家集训队]数颜色 / 维护队列 带修莫队
题目描述 墨墨购买了一套\(N\)支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: \(1\). \(Q\) \(L\) \(R\)代表询问你从第\(L\) ...
- P1903 [国家集训队]数颜色 / 维护队列 带修改的莫队
\(\color{#0066ff}{ 题目描述 }\) 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支 ...
- P1903 [国家集训队]数颜色 / 维护队列 带修改莫队
题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2 ...
- P1903 [国家集训队]数颜色 / 维护队列
思路 带修莫队的板子 带修莫队只需要多维护一个时间的指针即可,记录一下每个询问在第几次修改之后,再回退或者前进几个修改操作 排序的时候如果a.l和b.l在一个块里,就看r,如果a.r和b.r在一个块里 ...
- P1903 [国家集训队]数颜色 / 维护队列(带修莫队)
题目描述: 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. ...
随机推荐
- bzoj3160
fft+manacher fft都快忘了... 其实我们发现,这个问题是可以用fft做的,因为是回文子序列,所以我们直接自己和自己求卷积,然后扫描每个位置,注意是每个位置,因为包括奇数长度和偶数长度, ...
- MFC project for a non-Unicode character set is deprecated
error MSB8031: Building an MFC project for a non-Unicode character set is deprecated. You must chang ...
- bzoj 1079: [SCOI2008]着色方案【记忆化搜索】
本来打算把每个颜色剩下的压起来存map来记忆化,写一半发现自己zz了 考虑当前都能涂x次的油漆本质是一样的. 直接存五个变量分别是剩下12345个格子的油漆数,然后直接开数组把这个和步数存起来,记忆化 ...
- nc的基本用法
nc(netcat) 被誉为网络安全界的‘瑞士军刀’,可以用于完成几乎涉及TCP.UDP或者Unix域套接字的任何事.它可以打开TCP连接,发送UDP报文,在任意的TCP和UDP端口监听,进行端口扫描 ...
- Elementui实战知识点随记
1. Elementui实战知识点随记 1.1. 表单验证 对于复杂数据,类似于对象里面包含数组,每个数组又包含多个对象,表单验证我查看了网上很多资料都说Elementui不支持,实际上,经过我官网的 ...
- 数据结构 - 顺序队列的实行(C语言)
数据结构-顺序队列的实现 1 顺序队列的定义 线性表有顺序存储和链式存储,队列作为一种特殊的线性表,也同样存在这两种存储方式.我们先来看队列的顺序存储结构. 队列的顺序储存结构:用数组存储队列,为了避 ...
- [Usaco2008 Dec]Hay For Sale 购买干草
Description 约翰遭受了重大的损失:蟑螂吃掉了他所有的干草,留下一群饥饿的牛.他乘着容量为C(1≤C≤50000)个单位的马车,去顿因家买一些干草. 顿因有H(1≤H≤5000)包干草,每一 ...
- C#中的list的System.Predicate<in T>和System.Comparison<in T>的应用
public class Data { ; ; ; ; public Data() { count++; ma = count; } } //一句话删除满足要求的集合 Asm.RemoveAll((D ...
- MVC C# 直接导出txt文件
用asp.net根据数据内容自动生成一个txt文本文件并提供用户下载,此方法文件不保存在服务器上,直接提供给用户下载,到网上搜了一下,都是用的Response.BinaryWrite(),用了几下,发 ...
- ssm基础配置
1.导包 <dependencies> <dependency> <groupId>org.springframework</groupId> < ...