您的位置:首页 > 其它

BZOJ 3585: mex [主席树]

2017-01-28 23:28 363 查看

3585: mex

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 787 Solved: 422
[Submit][Status][Discuss]

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

By 佚名提供

参考:http://blog.csdn.net/werkeytom_ftd/article/details/50975467

感觉是非常神的做法

建立权值线段树,每个位置i保存数字i出现的最右端

查询[l,r],就是找第r棵前缀线段树中第一个值<l的

维护区间最小值就可以做到了

//
//  main.cpp
//  bzoj3585
//
//  Created by Candy on 2017/1/28.
//  Copyright © 2017年 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lc(x) t[x].l
#define rc(x) t[x].r
const int N=2e5+5,MX=1e8+5;
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,Q,a
,l,r;
struct node{
int l,r,mn;
}t[N*30];
int sz,root
;
void ins(int &x,int l,int r,int p,int v){//right of p is v
t[++sz]=t[x];x=sz;
if(l==r) t[x].mn=v;
else{
int mid=(l+r)>>1;
if(p<=mid) ins(t[x].l,l,mid,p,v);
else ins(t[x].r,mid+1,r,p,v);
t[x].mn=min(t[lc(x)].mn,t[rc(x)].mn);
}
}
int query(int x,int l,int r,int v){
if(l==r) return l;
else{
int mid=(l+r)>>1;
if(t[lc(x)].mn<v) return query(t[x].l,l,mid,v);
else return query(t[x].r,mid+1,r,v);
}
}
int main(int argc, const char * argv[]) {
n=read();Q=read();
for(int i=1;i<=n;i++) a[i]=read(),root[i]=root[i-1],ins(root[i],0,MX,a[i],i);
while(Q--){
l=read();r=read();
printf("%d\n",query(root[r],0,MX,l));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: