题目描述

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

输入格式

第一行n,m。

第二行为n个数。

从第三行开始,每行一个询问l,r。

输出格式

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

一开始以为像答案这样的做法会超时,没想到真是这样写。。。

 #include<cstdio>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
const int maxn=2e5+;
int num[maxn];
int answer,block;
int vis[maxn];
struct node
{
int l,r,id;
int Ans;
}ans[maxn];
bool cmp(node x,node y)
{
if(x.l/block!=y.l/block)
return x.l<y.l;
if(x.l/block&) //使用波形排序,可进一步的优化
return x.r<y.r;
return x.r>y.r;
}
bool CMP(node x,node y)
{
return x.id<y.id;
}
void Delete(int pos)
{
vis[num[pos]]--;
if(!vis[num[pos]]&&num[pos]<answer){
answer=num[pos];
}
}
void add(int pos)
{
vis[num[pos]]++;
if(vis[num[pos]]==&&answer==num[pos]){
int tmp=answer+;
while(){
if(!vis[tmp]){
answer=tmp;
return;
}
tmp++;
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
block=sqrt(n);
for(int i=;i<=n;i++) scanf("%d",&num[i]);
for(int i=;i<=m;i++){
scanf("%d%d",&ans[i].l,&ans[i].r);
ans[i].id=i;
}
sort(ans+,ans++m,cmp);
int left=,right=;
for(int i=;i<=m;i++){
while(ans[i].l>left) Delete(left++);
while(ans[i].l<left) add(--left);
while(ans[i].r>right) add(++right);
while(ans[i].r<right) Delete(right--);
ans[i].Ans=answer;
}
sort(ans+,ans++m,CMP);
for(int i=;i<=m;i++)
printf("%d\n",ans[i].Ans);
return ;
}

还有一个权值线段树的解法:

对于第i棵权值线段树,维护一下数列前ii项中每个权值出现的最靠右的位置。然后向上更新一下最小值。这样如果某个权值最靠右的位置都比查询区间左端点小的话,那它一定没有在这个区间里出现。维护最小值目的就是看最小的是否比左端点大,根据这个在线段树上二分。

权值范围是10^9109的。题解里有说答案最大为nn,直接把>n>n的a[i]a[i]处理为n+1n+1就行。蒟蒻没有想到QAQQAQ,说一下蒟蒻的处理:

用离散化,但是一个权值没有在数列里出现过的话就不会在离散化数组中,也不会出现在线段树中,查询会出锅。注意到一个询问的答案要么是00,要么是数列中某个数的值+1+1。这样离散化时把00和每个出现过的权值+1+1都丢进去就行了QwQQwQ。

当然这道题不强制在线也不修改,可以把询问离线下来一边扫一边加,遇到询问右端点就查询左端点,不需要主席树(可持久化线段树),一棵权值线段树就可以了。

时间复杂度:O(nlogn)

 #include<cstdio>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<vector>
using namespace std;
const int maxn=2e5+;
int ans[maxn];
int t; //T为离散化之后的数组长度
int a[maxn],b[maxn*],cnt; //原数组和离散化的数组,以及下标cnt;
int tree[maxn<<];
int root[maxn];
void update(int root)
{
tree[root]=min(tree[root<<],tree[root<<|]);
}
void add(int num,int l,int r,int root,int base)
{
if(l==r){
tree[root]=base;
return;
}
int mid=l+r>>;
if(num<=mid) add(num,l,mid,root<<,base);
else add(num,mid+,r,root<<|,base);
update(root);
}
int query(int pos)
{
int l=,r=t;
int root=;
while(l<r){
int mid=l+r>>;
//如果左区间的值至少存在一个权值的下标小于pos的,就证明此范围内有符合条件的数;
//就像左边二分;
if(tree[root<<]<pos) r=mid,root=root<<;
//否则向右边二分;
else l=mid+,root=root<<|;
}
return b[l];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
b[++cnt]=;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
b[++cnt]=a[i];
b[++cnt]=a[i]+;
}
sort(b+,b++cnt);
t=unique(b+,b++cnt)-b-;
for(int i=;i<=n;i++){
a[i]=lower_bound(b+,b++t,a[i])-b;
add(a[i],,t,,i,root[i],root[i-]);
}
return ;
}

因为权值线段树能解这道题,所以用主席树解就显得没有必要了,但我还是练了练手。

 #include<cstdio>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
const int maxn=4e5+;
int a[maxn],b[maxn],cnt=,len;
struct node{int l,r,id;}tree[maxn<<];int cot;
//主席树需要开的空间比一般线段树更大,另外后面的cot是记录主席树节点用的。
int Root[maxn];
void build(int &x,int l,int r)
{
//这里的&x会把x得到的值传给这个变量,也就是Root[0];
//建一波空树,其实可以不建的,之前打过不建的代码,
//但总觉得不建的话心里不踏实。啊哈哈哈
x=++cot;
if(l==r) return ;
int mid=l+r>>;
build(tree[x].l,l,mid);
build(tree[x].r,mid+,r);
}
void add(int num,int l,int r,int &x,int y,int pos)
{
//同上,这里的&x会传给root[i];
tree[++cot]=tree[y];
x=cot; //将cot传给x,这个cot储存的是Root[i]这个节点的值,这个节点是根节点。
if(l==r){
tree[cot].id=pos;
//tree[x].id=pos; 这里也可以这样写
return;
}
int mid=l+r>>;
if(num<=mid) add(num,l,mid,tree[x].l,tree[y].l,pos);
else add(num,mid+,r,tree[x].r,tree[y].r,pos);
int left=tree[x].l,right=tree[x].r;
tree[x].id=min(tree[left].id,tree[right].id); //传递最小值;
}
int query(int pos,int base)
{
//这一部分是本题内容。
int l=,r=len;
while(l<r){
int mid=l+r>>;
//left存储的是根节点的左区间,right为右区间。
int left=tree[base].l,right=tree[base].r;
if(tree[left].id<pos) r=mid,base=left;
else l=mid+,base=right;
}
return b[l];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
b[++cnt]=;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
b[++cnt]=a[i];
b[++cnt]=a[i]+;
}
sort(b+,b++cnt);
len=unique(b+,b++cnt)-b-;
build(Root[],,len);
for(int i=;i<=n;i++){
a[i]=lower_bound(b+,b++len,a[i])-b;
add(a[i],,len,Root[i],Root[i-],i);
}
for(int i=;i<=m;i++){
int l,r;
scanf("%d%d",&l,&r);
int ans=query(l,Root[r]);
printf("%d\n",ans);
}
return ;
}

莫队或权值线段树 或主席树 p4137的更多相关文章

  1. HDU - 2665 Kth number 主席树/可持久化权值线段树

    题意 给一个数列,一些询问,问$[l,r]$中第$K$大的元素是哪一个 题解: 写法很多,主席树是最常用的一种之一 除此之外有:划分树,莫队分块,平衡树等 主席树的定义其实挺模糊, 一般认为就是可持久 ...

  2. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  3. [BZOJ5139][Usaco2017 Dec]Greedy Gift Takers 权值线段树

    Description Farmer John's nemesis, Farmer Nhoj, has NN cows (1≤N≤10^5), conveniently numbered 1…N. T ...

  4. 【BZOJ4605】崂山白花蛇草水 权值线段树+kd-tree

    [BZOJ4605]崂山白花蛇草水 Description 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了 ...

  5. 【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree

    题目描述 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob ...

  6. 崂山白花蛇草水 权值线段树套KDtree

    Description 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实 力,他轻松地进了山东省省队,现在便是他履行诺言的时 ...

  7. 洛谷P4848 崂山白花蛇草水 权值线段树+KDtree

    题目描述 神犇 \(Aleph\) 在 \(SDOI\ Round2\) 前立了一个 \(flag\):如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇 \(Aleph\) 的实力,他轻松地进了山 ...

  8. 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

    谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结 ...

  9. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

随机推荐

  1. 0004 工程配置settings.py

    两个目录的区别: 工程目录是指包含manage.py文件的目录 配置目录是批包含settings.py文件的目录 在配置目录中找到并打工settings.py文件,做以下配置: 01 DEBUG DE ...

  2. web服务器、Web中间件和Web容器的区别

    web服务器>web中间件>web容器 Tomcat(servlet容器)  是  Tomcat中间件  也是  Tomcat服务器 看了谢公子的csdn文章,让我彻底分清了这三者的区别. ...

  3. Android_几种菜单

    Android中的菜单有如下几种: OptionMenu:选项菜单,android中最常见的菜单,通过Menu键来调用 SubMenu:子菜单,android中点击子菜单将弹出一个显示子菜单项的悬浮框 ...

  4. vue formatter element表格处理数据

    formatter 指定一个vue methods 方法 作用:对从数据库中取出的数据进行处理后展示. <el-table-column prop="partner1" // ...

  5. WordPress 背后的故事竟然是这样

    原文链接:The Story Behind the New WordPress.com 译者:杰微刊-Leo Xu 一年半以前,我们对使用 WordPress 构建网站所需要采用的技术和开发流程进行大 ...

  6. AntDesign(React)学习-2 第一个页面

    1.前面创建了第一个项目jgdemo,结构如下,使用TypeScript. 2.yarn start启动项目 3.点击GettingStarted是umi的官方网站 https://umijs.org ...

  7. [JZOJ4899] 雪之国度

    题目描述 雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路.雪之女王赋予了每一座城市不同的能量,其中第i座城 ...

  8. python之路函数

    1.函数参数,引用 2.lambda表达式 lambda表达式 f1 = lambda a1,a2: a1+a2 3.python的内置函数 abs(),绝对值 all(),循环参数,如果每个元素都为 ...

  9. R data formats

    R data formats: Rdata Rda Rds 1.概念 rds是R语言中利用二进制保存的源文件,加载readr包以后,使用write_rds(x,file='x.rds')保存文件,re ...

  10. Go键盘输入与打印输出

    输出 格式化打印占位符 符号 说明 %v 默认格式 %T 打印类型 %t 布尔类型 %s 字符串 %f 浮点数 %d 十进制的整数 %b 二进制的整数 %o 八进制 %x 十六进制0-9 a-f %X ...