题目描述:

墨墨购买了一套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≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

本题可能轻微卡常数

思路:

本题为带修莫队模板题,在普通莫队的基础上引入时间维度,可以支持时间推移和时间倒流。跑主算法时定义当前时间戳为t,对于每个查询操作,如果当前时间戳大于查询的时间戳,说明已进行的修改操作比要求的多,就把之前改的改回来,如果当前时间戳小于查询的时间戳,说明还应再往后修改。只有当当前区间和查询区间左右端点、时间戳均重合时,才认定区间完全重合,此时的答案才是本次查询的最终答案。

在排序中加入第三关键字t(时间),按着l到r再到t的顺序排,分块大小应为n^(2/3),在最后for循环的while中加入两个关于时间的while来调整当前时间与查询时间的关系。

因为移完t t做完一处修改后,有可能要改回来,所以我们还要把原值存好备用。但其实我们也可以不存,只要在修改后把修改操作的值和原值swap一下,那么改回来时也只要swap一下,swap两次相当于没搞,就改回来了。

代码::

 #include <iostream>
#include <cmath>
#include <algorithm>
#define max_n 50005
using namespace std;
int n,m;
int a[max_n];
int belong[max_n*];
int ans[max_n];
int cnt[]; struct query
{
int l;
int r;
int id;
int t;
}q[max_n];
struct modify
{
int pos;
int col;
int last;
}c[max_n];
int size;
int bulk;
int cntq = ;
int cntc = ;
int cmp(query a,query b)
{
return (belong[a.l]^belong[b.l])? belong[a.l]<belong[b.l]:((belong[a.r]^belong[b.r])?belong[a.r]<belong[b.r]:a.t<b.t);
}
int main()
{
cin >> n >> m;
size = pow(n,2.0/3.0);
bulk = ceil((double)n/size);
for(int i = ;i<=bulk;i++)
{
for(int j = (i-)*size+;j<=i*size;j++)
{
belong[j] = i;
}
}
for(int i = ;i<=n;i++)
{
cin >> a[i];
}
char opt;
for(int i = ;i<=m;i++)
{
cin >> opt;
switch(opt)
{
case 'Q':
cin >> q[++cntq].l;
cin >> q[cntq].r;
q[cntq].t = cntc;
q[cntq].id= cntq;
break;
case 'R':
cin >> c[++cntc].pos;
cin >> c[cntc].col;
}
}
sort(q+,q+cntq+,cmp);
int l = ;
int r = ;
int time = ;
int now = ;
for(int i = ;i<=cntq;i++)
{
int ql = q[i].l;
int qr = q[i].r;
int qt = q[i].t;
while(l<ql) now -= !--cnt[a[l++]];
while(l>ql) now += !cnt[a[--l]]++;
while(r>qr) now -= !--cnt[a[r--]];
while(r<qr) now += !cnt[a[++r]]++;
while(time<qt)
{
++time;//时间向后推移
if(ql<=c[time].pos&&c[time].pos<=qr)//如果当前(time时)位置与查询区间重合,说明time时已经统计过c[time].pos处的元素,并且是以旧的时间的未修改的这个元素完成统计的
{//压缩的运算表达式
now -= !--cnt[a[c[time].pos]]-!cnt[c[time].col]++;
//now是存的答案,c[time].pos是在time时修改的位置,a[c[time].pos]是在该位置原来的元素,注意now后是-=
//这句含义是1.如果在time时刻修改的位置(因为现在是时间还在往前走)上的元素的个数减少到零,now就减少一(因为这个元素已成为历史)
//c[time].col是在time时刻修改后的颜色
//2.如果对于在time时刻修改过的元素,它的个数为0,就将元素个数自增,然后now在加一(因为随着时间推移,发现了新的元素种类)
}
swap(a[c[time].pos],c[time].col);
//让这个新元素(c[time].col)成为历史,用a[c[time].pos]暂时存储,
//而c[time].col里是暂存原来被修改掉的元素
}
while(qt<time)
{
if(ql<=c[time].pos&&c[time].pos<=qr)
{
now -= !--cnt[a[c[time].pos]]-!cnt[c[time].col]++;
//同上
}
swap(a[c[time].pos],c[time].col);
//同上
--time;
}
ans[q[i].id] = now;
}
for(int i = ;i<=cntq;i++)
{
cout << ans[i] << endl;
}
return ;
}

P1903 [国家集训队]数颜色 / 维护队列(带修莫队)的更多相关文章

  1. 洛谷 P1903 [国家集训队]数颜色 / 维护队列 带修莫队

    题目描述 墨墨购买了一套\(N\)支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: \(1\). \(Q\) \(L\) \(R\)代表询问你从第\(L\) ...

  2. Luogu P1903 [国家集训队]数颜色 / 维护队列 (带修莫队)

    #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> ...

  3. P1903 [国家集训队]数颜色 / 维护队列 带修改莫队

    题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2 ...

  4. luogu 1903 [国家集训队]数颜色 / 维护队列 带修改莫队

    十分玄学的数据结构~ code: #include <bits/stdc++.h> #define N 1000006 #define setIO(s) freopen(s".i ...

  5. P1903 [国家集训队]数颜色 / 维护队列 带修改的莫队

    \(\color{#0066ff}{ 题目描述 }\) 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支 ...

  6. bzoj2120 / P1903 [国家集训队]数颜色 / 维护队列(带修改莫队)

    P1903 [国家集训队]数颜色 / 维护队列 带修改的莫队 在原有指针$(l,r)$上又添加了时间指针$t$ 贴一段dalao的解释 带修改的莫队,和原版莫队相比,多了一个时间轴 原版莫队是将区间( ...

  7. 洛谷P1903 [国家集训队]数颜色 / 维护队列 ( 带 修 )

    题意:有两种操作: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 对每个1操作 输出答案: 带修莫队 模板题 (加 ...

  8. P1903 [国家集训队]数颜色 / 维护队列

    思路 带修莫队的板子 带修莫队只需要多维护一个时间的指针即可,记录一下每个询问在第几次修改之后,再回退或者前进几个修改操作 排序的时候如果a.l和b.l在一个块里,就看r,如果a.r和b.r在一个块里 ...

  9. LUOGU P1903 [国家集训队]数颜色 / 维护队列

    传送门 解题思路 带修莫队,第一次写,其实和普通莫队差不多,就是多了个时间轴,块分n^(2/3)最优,时间复杂度O(n^(5/3)). #include<iostream> #includ ...

随机推荐

  1. [LeetCode] 282. Expression Add Operators 表达式增加操作符

    Given a string that contains only digits 0-9 and a target value, return all possibilities to add bin ...

  2. SQL Server跨服务器操作数据库

    今天给大家来分享一下跨服务器操作数据库,还是以SQL Server的管理工具(SSMS)为平台进行操作. 什么是跨服务器操作? 跨服务器操作就是可以在本地连接到远程服务器上的数据库,可以在对方的数据库 ...

  3. Dynamic Property Wizard 添加类提示 ATL类只能添加到MFC EXE 和MFC规则DLL项目或完全支持ATL的项目 错误提示解决方式

    在重新打开OPM项目添加ATL动态属性向导Dynamic Property Wizard提示错误 ATL类只能添加到MFC EXE 和MFC规则DLL项目或完全支持ATL的项目. 有效的解决方式,右键 ...

  4. 【转】Axure RP9.0.0.3661Team Edition激活码

    被授权人:Axure 授权密码:ydiJnG8quHEhHLu/MWonjkeul5LYB1+tX9fyPVnpdmU0cb/NJzVs45uD7z5Iswmi 转载于:http://menvscod ...

  5. 怎么又出错了?盘点java中最容易出现的错误

    现如今,java已经广泛应用各种软件开发领域.基于面向对象的设计,java屏蔽了诸如C,C++等语言的一些复杂性,提供了垃圾回收机制,平台无关的虚拟机技术,Java创造了一种前所未有的开发方式.所以, ...

  6. python三大器之装饰器的练习

    装饰器 加载顺序从下至上 执行顺序从上至下 ''' 多层装饰器 ''' def deco1(func): #func=deco2 def wrapper1(*args, **kwargs): '''t ...

  7. 18年10月 python 中出现 ValueError: need more than 1 value to unpack 解决办法 (笨办法)

    eg:a,b = argv    :错误,我的理解也许不正确,但是能解决办法 a,b=  argv,argv 正确 :经测试不会出现错误. ------------------------------ ...

  8. 状态机的Verilog写法

    “硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这就要用到状态机思想.什么是状态机呢?简单的说,就是通 ...

  9. python ID3决策树实现

    环境:ubuntu 16.04 python 3.6 数据来源:UCI wine_data(比较经典的酒数据) 决策树要点: 1. 如何确定分裂点(CART ID3 C4.5算法有着对应的分裂计算方式 ...

  10. ASP.Net Core 2.1+ Cookie 登录授权验证【简单Cookie验证】

    介绍 本文章发布于博客园:https://www.cnblogs.com/fallstar/p/11310749.html 作者:fallstar 本文章适用于:ASP.NET Core 2.1 + ...