对于区间查询的问题,提供一种思路:

莫队。

莫队是处理区间问题的乱搞神器,尤其是对于离线查询问题,当然也可以做在线查询,比如带修莫队。

对于有的题,莫队是乱搞骗分,而在某些地方,莫队是正解。

这道题来说,可以当做是萌新初学莫队的一个板子,而且莫队也好理

解。线段树树状数组这类也可以做,但是相比莫队而言麻烦些。(个

人见解,不喜勿喷。谢谢)


1st.关于莫队的思想:

先明白一点,莫队可以理解成:

优雅的暴力。

暴力算法几乎人人都会,所以莫队理解起来好理解。

如果让你暴力的话呢?

我们用一个cnt[ ]数组记录每种元素,用桶排的思想,枚举区间,每遇到一个元素对应的桶++,然后暴力一遍所有的桶,等于1的我们ans就++,这样统计不同的个数,看看是不是等于L到R,然后再清空桶和ans,做下一组询问。

对于一般的暴力算法往往会TLE,那么莫队是怎么做的呢?

首先:考虑我们有两个指针。一个叫做curL,另一个叫curR。他们对应的是所指的数的标号。这样我们可以利用这两个指针进行移动,每次只能向左或向右移动一步。移动的复杂度是O(1)。

eg:

我们现在处理了curL—curR区间内的数据,现在左右移动,比如curL到curL-1,只需要更新上一个新的3,即curL-1。

那么curL到curL+1,我们只需要去除掉当前curL的值。因为curL+1是已经维护好了的。

curR同理,但是要注意方向哦!curR到curR+1是更新,curR到cur-1是去除。

我们先计算一个区间 [curL curR] 的answer,这样的话,我们就可以用O(1)转移到 [curL-1 curR] [curL+1 curR] [curL curR+1] [curL curR-1] 上来并且求出这些区间的answer。

我们利用curL和curR,就可以移动到我们所需要求的[L R]上啦~

这样做会快很多,但是......

如果有个**数据,让你在每个L和R间来回跑,而且跨度很大呢??

我们每次只动一步,岂不是又T了??

但是这其实就是莫队算法的核心了。我们的莫队算法还有优化。

这就是莫队算法最精明的地方(我认为的qwq)

我们想,因为每次查询是离线的,所以我们先给每次的查询排一个序。

排序的方法是

分块。

我们把所有的元素分成多个块(即分块)。分了块跑的会更快。再按照右端点从小到大,左端点块编号相同按右端点从小到大。

为什么要这么排序呢?

如果不是按照分块排序,那么一种直观的办法是按照左端点排序,再按照右端点排序。但是这样的表现不好。特别是面对精心设计的数据,这样方法表现得很差。

举个栗子,有6个询问如下:(1, 100), (2, 2), (3, 99), (4, 4), (5, 102), (6, 7)。

这个数据已经按照左端点排序了。用上述方法处理时,左端点会移动6次,右端点会移动移动98+97+95+98+95=483次。

其实我们稍微改变一下询问处理的顺序就能做得更好:(2, 2), (4, 4), (6, 7), (5, 102), (3, 99), (1, 100)。

左端点移动次数为2+2+1+2+2=9次,比原来稍多。右端点移动次数为2+3+95+3+1=104,右端点的移动次数大大降低了。

上面的过程启发我们:我们不应该严格按照升序排序,而是根据需要灵活一点的排序方法

这样,不断地移动端点指针+精妙的排序,就是普通莫队的思想啦~


2ec.Code

1.对于每组查询的记录和排序:

l,r为左右区间编号,p是第几组查询的编号(记录下来为了排序后不打乱顺序还按照原查询的顺序输出),bl是分块数。

struct query{
int l, r, p;
}e[maxn]; bool cmp(query a, query b)
{
return (a.l/bl) == (b.l/bl) ? a.r < b.r : a.l < b.l;
}

2.处理和初始变量:

answer就是所求答案, bl是分块数量, a[]是原序列, ans[]是记录原查询序列下的答案, cnt[]是记录对于每个数i, cnt[i]表示i出现过的次数, curL和curR不再解释, nm看题意要求。 add和del每个题有不同的写法。

int answer, a[maxn], m, n, bl, ans[maxn], cnt[maxn], k, curL = 1, curR = 0;
void add(int pos)//添加
{
//do sth...
}
void del(int pos)//去除
{
//do sth...
}
//一般写法都是边处理 边根据处理求答案。cnt[a[pos]]就是在pos位置上原序列a出现的次数。

3.主体部分及输出:

预处理查询编号,用四个while移动指针顺便处理。

在这里着重说下四个while

我们设想有一条数轴:

当curL < L 时,我们当前curL是已经处理好的了。所以del时先去除当前curL再++

当curL > L 时,我们当前curL是已经处理好的了。所以 add 时先 -- 再加上改后的curL

当curR > R 时,我们当前curR是已经处理好的了。所以del时先去除当前curR再 --

当curR < R 时,我们当前curR是已经处理好的了。所以 add 时先++再加上改后的curR

n = read(); m = read(); k = read();
bl = sqrt(n); for(int i = 1; i <= n; i++)
a[i] = read(); for(int i = 1; i <= m; i++)
{
e[i].l = read(); e[i].r = read();
e[i].p = i;
} sort(e+1,e+1+m,cmp); for(int i = 1; i <= m; i++)
{
int L = e[i].l, R = e[i].r;
while(curL < L)
del(curL++);
while(curL > L)
add(--curL);
while(curR > R)
del(curR--);
while(curR < R)
add(++curR);
ans[e[i].p] = answer;
}
for(int i = 1; i <= m; i++)
printf("%d\n",ans[i]);
return 0;

3th.关于这题题解

我的想法还是蛮暴力的,对于出现过的数直接记录下来,answer记录出现了多少个不同的数,如果answer等于现在的R-L+1,那么说明出现的数与L到R相同。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ri register
using namespace std;
const int maxn = 100010;
inline int read()
{
int k=0;
char c;
c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c)){k=(k<<3)+(k<<1)+c-'0';c=getchar();}
return k;
}
int n, m, bl, answer = 0, curL, curR, cnt[maxn], a[maxn];
bool ans[maxn];
struct Query{
int l, r, p;
}q[maxn];
bool cmp(const Query &a, const Query &b)
{
return (a.l/bl) == (b.l/bl) ? a.r < b.r : a.l < b.l;
}
void add(int pos)
{
if((++cnt[a[pos]]) == 1) ++answer;
}
void del(int pos)
{
if((--cnt[a[pos]]) == 0) --answer;
}
int main()
{
n = read();
m = read();
bl = sqrt(n);
for(ri int i = 1; i <= n; i++)
a[i] = read(); for(ri int i = 1; i <= m; i++)
{
q[i].l = read();
q[i].r = read();
q[i].p = i;
} sort(q+1,q+1+m,cmp); for(ri int i = 1; i <= m; i++)
{
int L = q[i].l, R = q[i].r;
while(curL < L) del(curL++);
while(curL > L) add(--curL);
while(curR < R) add(++curR);
while(curR > R) del(curR--);
if(answer == (R-L+1))
ans[q[i].p] = 1;
}
for(ri int i = 1; i <= m; i++)
{
if(ans[i] == 1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}

如果对于莫队算法有什么疑问或者对我的题解有什么建议欢迎和我讨论,本人会尽力解答和虚心接受意见的。

【luogu P3901 数列找不同】 题解的更多相关文章

  1. Luogu P3901 数列找不同

    由于技术原因,题目我贴不上了,大家点下面的链接自己去看吧^_^ P3901 数列找不同 这题第一眼看去,题面真短,有坑(flag) 在往下面看去,woc数据这么大,你要怎样. 现在一起想想想,超级侦探 ...

  2. 【题解】Luogu P3901 数列找不同

    我博客中对莫队的详细介绍 原题传送门 不错的莫队练手题 块数就直接取sqrt(n) 对所有询问进行排序 排序第一关键词:l所在第几块,第二关键词:r的位置 考虑Ai不大,暴力开数组 add时如果加之后 ...

  3. P3901 数列找不同

    P3901 数列找不同 题目描述 现有数列 \(A_1,A_2,\cdots,A_N\) ,Q 个询问 \((L_i,R_i)\) , \(A_{Li} ,A_{Li+1},\cdots,A_{Ri} ...

  4. 【刷题】洛谷 P3901 数列找不同

    题目描述 现有数列 \(A_1,A_2,\cdots,A_N\) ,Q 个询问 \((L_i,R_i)\) , \(A_{Li} ,A_{Li+1},\cdots,A_{Ri}\) 是否互不相同 输入 ...

  5. 洛谷 P3901 数列找不同(莫队)

    题目链接:https://www.luogu.com.cn/problem/P3901 这道题简单莫队模板题,然后$add$和$del$分别处理$vis[]$从$0-->1$和从$1--> ...

  6. 洛谷P3901 数列找不同 [莫队]

    题目传送门 题目描述 现有数列 A_1,A_2,\cdots,A_NA1​,A2​,⋯,AN​ ,Q 个询问 (L_i,R_i)(Li​,Ri​) , A_{Li} ,A_{Li+1},\cdots, ...

  7. 洛谷P3901 数列找不同(莫队)

    传送门 我不管我不管我就是要用莫队 直接用莫队裸上 //minamoto #include<iostream> #include<cstdio> #include<alg ...

  8. 洛谷P3901 数列找不同(莫队水题)

    重温下手感,判断区间是否全是不同的数字有两种做法,一个长度为len的区间不同的数字,参见HH的项链,一种是区间众数,参见蒲公英,是水题没错了.明天搞数据库,然后继续自己的gre和训练计划 #inclu ...

  9. [Luogu 3398] 仓鼠找sugar

    [Luogu 3398] 仓鼠找sugar 又是 LCA- 前两天死活写不过的一个题今天终于顺手切了. 思路嘛参考了一楼题解. 就是说,对于 a, b, c, d 四个点, 令 x = LCA(a, ...

随机推荐

  1. spark on yarn模式里需要有时手工释放linux内存

    为什么要提出这个问题? spark跑YARN模式或Client模式提交任务不成功(application state: ACCEPTED) 然后执行 [spark@master spark--bin- ...

  2. 转-------基于R-CNN的物体检测

    基于R-CNN的物体检测 原文地址:http://blog.csdn.net/hjimce/article/details/50187029 作者:hjimce 一.相关理论 本篇博文主要讲解2014 ...

  3. 进入保护模式(一)——《x86汇编语言:从实模式到保护模式》读书笔记12

    之前已经做了一些理论上的铺垫,这次我们就可以看代码了. 一.代码清单 ;代码清单11-1 ;文件名:c11_mbr.asm ;文件说明:硬盘主引导扇区代码 ;创建日期:2011-5-16 19:54 ...

  4. 0.数据结构(python语言) 基本概念 算法的代价及度量!!!

    先看思维导图: *思维导图有点简陋,本着循循渐进的思想,这小节的知识大多只做了解即可. *重点在于算法的代价及度量!!!查找资料务必弄清楚. 零.四个基本概念 问题:一个具体的需求 问题实例:针对问题 ...

  5. 写C#代码时用到的中文简体字 、繁体字 对应的转化 (收藏吧)

    简体字    下面有与之对应的繁体字 private const String Jian = "啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆疤巴拔跋靶 ...

  6. Java线程同步打印ABC

    需求: 三个线程,依次打印ABCABCABC.... 方案一: 使用阻塞队列,线程1从队列1获取内容打印,线程2从队列2获取内容打印,线程3从队列3中获取内容打印.线程1把B放到队列3中,线程2把C放 ...

  7. 移除script标签引起的兼容性问题

    一.应用场景: 有时候我们需要动态创建script标签实现脚本的按需加载,我们会为script标签绑定onload或者onreadystatechange事件,用于检测动态脚本是否加载并执行完毕,在事 ...

  8. Windows10 iis10 arr webfarm

    win10安装arr提示安装失败,但是安装说明中提升iis7及以上版本,iis10却安装失败,坑爹!安装方法: 1.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSe ...

  9. 科学计算基础包——Numpy

    一.NumPy简介 NumPy是高性能科学计算和数据分析的基础包.它是pandas等其他各种工具的基础. 1.NumPy的主要功能 (1)ndarray:一个多维数组结构,高效且节省空间. (2)无需 ...

  10. null 和 undefined 区别

    ---恢复内容开始--- 1.在javascipt中,将一个变量赋值为undefined 或 null ,几乎没什么区别. 2. 在if语句中undefined  和 null 都会被自动转成fals ...