Description

  有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

Input

  第一行n,m。
  第二行为n个数。
  从第三行开始,每行一个询问l,r。

Output

  一行一个数,表示每个询问的答案。

Sample Input

5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5

Sample Output

1
2
3
0
3

HINT

数据规模和约定

  对于100%的数据:

  1<=n,m<=200000

  0<=ai<=109

  1<=l<=r<=n

  对于30%的数据:

  1<=n,m<=1000

Source

题目大意

  区间询问mex。

Solution 1 Mo's Algorithm & Block Division

  区间求mex?不会,直接莫队。

  由于一个数大于等于$n$时无意义,所以按$n$分块,每块记录是否完全被覆盖。

  查询时暴力跳。

  表示数据真水,最开始某个地方的$x$,写成$p$竟然A了。

Code

 /**
* bzoj
* Problem#3585
* Accepted
* Time: 6832ms
* Memory: 5988k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int cs = ; typedef class Query {
public:
int l, r;
int id; Query() { } boolean operator < (Query b) const {
if (l / cs != b.l / cs) return l < b.l;
return r < b.r;
}
}Query; int n, m;
int* ar;
Query* qs;
int exist[];
int cover[cs];
int *res; inline void init() {
scanf("%d%d", &n, &m);
ar = new int[(n + )];
qs = new Query[(m + )];
res = new int[(m + )];
for (int i = ; i <= n; i++)
scanf("%d", ar + i);
for (int i = ; i <= m; i++)
scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i;
} inline void update(int p, int sign) {
int x = ar[p];
if (x >= n) return;
if (!exist[x] && sign == ) cover[x / cs]++;
exist[x] += sign;
if (!exist[x] && sign == -)cover[x / cs]--;
} inline void solve() {
sort(qs + , qs + m + );
int mdzzl = , mdzzr = ;
for (int i = ; i <= m; i++) {
while (mdzzr < qs[i].r) update(++mdzzr, );
while (mdzzr > qs[i].r) update(mdzzr--, -);
while (mdzzl < qs[i].l) update(mdzzl++, -);
while (mdzzl > qs[i].l) update(--mdzzl, ); for (int j = ; j < cs; j++) {
if (cover[j] < cs) {
int k = j * cs;
while (exist[k]) k++;
res[qs[i].id] = k;
break;
}
}
} for (int i = ; i <= m; i++)
printf("%d\n", res[i]);
} int main() {
init();
solve();
return ;
}

分块&莫队

Solution 2 Segment Tree

  假设你通过某种方式求出了$[1, i]$的答案。

  考虑删掉位置1,那么位置上的数到下一次它出现之前都可以用来更新答案。

  于是线段树区间修改,单点查询,做完了。

Code

 /**
* bzoj
* Problem#3585
* Accepted
* Time: 4436ms
* Memory: 15184k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define smin(_a, _b) (_a > _b) ? (_a = _b) : (0) typedef class Query {
public:
int l, r, id, next;
}Query; typedef class SegTreeNode {
public:
int val;
SegTreeNode *l, *r; SegTreeNode():l(NULL), r(NULL) { }
}SegTreeNode; SegTreeNode pool[];
SegTreeNode* top = pool; SegTreeNode* newnode(int val) {
top->val = val;
return top++;
} typedef class SegTree {
public:
SegTreeNode* rt; SegTree() { }
SegTree(int n, int* f) {
build(rt, , n, f);
} void build(SegTreeNode*& p, int l, int r, int* f) {
p = newnode();
if (l == r) {
p->val = f[l];
return;
}
int mid = (l + r) >> ;
build(p->l, l, mid, f);
build(p->r, mid + , r, f);
} void update(SegTreeNode* p, int l, int r, int ql, int qr, int val) {
if (l == ql && r == qr) {
smin(p->val, val);
return;
}
int mid = (l + r) >> ;
if (qr <= mid)
update(p->l, l, mid, ql, qr, val);
else if (ql > mid)
update(p->r, mid + , r, ql, qr, val);
else {
update(p->l, l, mid, ql, mid, val);
update(p->r, mid + , r, mid + , qr, val);
}
} int query(SegTreeNode* p, int l, int r, int idx) {
if (l == idx && r == idx)
return p->val;
int mid = (l + r) >> , rt = p->val, a = ;
if (idx <= mid)
a = query(p->l, l, mid, idx);
else
a = query(p->r, mid + , r, idx);
return (a < rt) ? (a) : (rt);
}
}SegTree; int n, m;
int *ar, *suf;
int *last, *res;
Query *qs;
int *h, *f;
SegTree st;
boolean *exist; inline void init() {
scanf("%d%d", &n, &m);
h = new int[(n + )];
f = new int[(n + )];
ar = new int[(n + )];
suf = new int[(n + )];
res = new int[(m + )];
qs = new Query[(m + )];
last = new int[(n + )];
exist = new boolean[(n + )];
fill(h, h + n + , );
fill(suf, suf + n + , n + );
fill(last, last + n + , );
fill(exist, exist + n + , false);
for (int i = , x; i <= n; i++) {
scanf("%d", ar + i);
if (ar[i] >= n) continue;
x = ar[i];
if (last[x])
suf[last[x]] = i;
last[x] = i;
}
for (int i = ; i <= m; i++) {
scanf("%d%d", &qs[i].l, &qs[i].r);
qs[i].id = i, qs[i].next = h[qs[i].l], h[qs[i].l] = i;
}
} inline void prepare() {
int p = ;
for (int i = ; i <= n; i++) {
if (ar[i] < n)
exist[ar[i]] = true;
while (exist[p]) p++;
f[i] = p;
}
st = SegTree(n, f);
} inline void solve() {
for (int i = ; i <= n; i++) {
for (int j = h[i]; j; j = qs[j].next)
res[qs[j].id] = st.query(st.rt, , n, qs[j].r);
if (ar[i] < n) {
st.update(st.rt, , n, i, suf[i] - , ar[i]);
}
}
for (int i = ; i <= m; i++)
printf("%d\n", res[i]);
} int main() {
init();
prepare();
solve();
return ;
}

bzoj 3585 mex - 线段树 - 分块 - 莫队算法的更多相关文章

  1. BZOJ.3585.mex(线段树)

    题目链接 题意:多次求区间\(mex\). 考虑\([1,i]\)的\(mex[i]\),显然是单调的 而对于\([l,r]\)与\([l+1,r]\),如果\(nxt[a[l]]>r\),那么 ...

  2. BZOJ 1878 [SDOI2009]HH的项链 (主席树 或 莫队算法)

    题目链接  HH的项链 这道题可以直接上主席树的模板 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) ...

  3. 【BZOJ-3809】Gty的二逼妹子序列 分块 + 莫队算法

    3809: Gty的二逼妹子序列 Time Limit: 80 Sec  Memory Limit: 28 MBSubmit: 1072  Solved: 292[Submit][Status][Di ...

  4. bzoj 2038 A-小Z的袜子[hose] - 莫队算法

    作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从 ...

  5. bzoj 3289 Mato的文件管理(莫队算法+BIT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3289 [题意] 回答若干个询问:[l,r]区间内的逆序对个数. [思路] 莫队算法,B ...

  6. bzoj 2308 小Z的袜子(莫队算法)

    小Z的袜子 [题目链接]小Z的袜子 [题目类型]莫队算法 &题解: 莫队算法第一题吧,建议先看这个理解算法,之后在参考这个就可以写出简洁的代码 我的比第2个少了一次sort,他的跑了1600m ...

  7. bzoj 2038 小Z的袜子 莫队算法

    题意 给你一个长度序列,有多组询问,每次询问(l,r)任选两个数相同的概率.n <= 50000,数小于等于n. 莫队算法裸题. 莫队算法:将序列分为根号n段,将询问排序,以L所在的块为第一关键 ...

  8. 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex

    题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...

  9. BZOJ 3585: mex [主席树]

    3585: mex Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 422[Submit][Status][Discuss] ...

随机推荐

  1. Java自学-面向对象 属性

    Java类的属性 一个英雄有姓名,血量,护甲等等状态 这些状态就叫做一个类的属性 步骤 1 : 属性的类型 属性的类型可以是基本类型,比如int整数,float 浮点数 也可以是类类型,比如Strin ...

  2. npm安装时-S -D作用及区别

    -S 即--save(保存) 包名会被注册在package.json的dependencies里面,在生产环境下这个包的依赖依然存在 -D 即--dev(生产) 包名会被注册在package.json ...

  3. hadoop中HDFS的NameNode原理

    1. hadoop中HDFS的NameNode原理 1.1. 组成 包括HDFS(分布式文件系统),YARN(分布式资源调度系统),MapReduce(分布式计算系统),等等. 1.2. HDFS架构 ...

  4. React Children 使用

    React 有一个特殊的属性children, 主要用于组件需要渲染内容,但它并不知道具体要渲染什么内容,怎么会有这种使用场景?确实比较少,但并不是没有,比如弹出框.当你写一个弹出框组件的时候,你知道 ...

  5. Java 初识

    一.Java 简介 1.什么是 Java Java 语言是美国 Sun 公司(Stanford University Network),在1995年推出的高级的编程语言,所谓编程语言,是计算机的语言, ...

  6. MongoDB的集群模式--Sharding(分片)

    分片是数据跨多台机器存储,MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署. 具有大型数据集或高吞吐量应用程序的数据库系统可能会挑战单个服务器的容量.例如,高查询率会耗尽服务器的CP ...

  7. Linux chage命令详解

    原文 chage命令用于密码实效管理,该是用来修改帐号和密码的有效期限,接下来通过本文给大家介绍Linux chage命令相关知识,本文介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起学习吧 lin ...

  8. 环境搭建:添加 xgboost 到 Anaconda

    原文参考:https://blog.csdn.net/lvsehaiyang1993/article/details/80619495 原文博主:Big_quant

  9. 【Docker】Docker容器中安装netstat命令

    1)先执行 apt-get update 2) 再执行 apt-get install net-tools

  10. 10 分钟上手 Vim,常用命令大盘点

    传闻有 180 万的程序员不知道如何退出 Vim 编辑器,真的有这么困难吗?下面给大家整理了一份 Vim 常用命令,让你 10 分钟快速上手 Vim,溜得飞起! 以下命令请在普通模式执行 1.移动光标 ...