您的位置:首页 > 其它

[bzoj 3339&bzoj 3585]Rmq Problem&mex

2018-03-03 14:25 260 查看
有一个长度为n的数组{a1,a2,…,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

这道题仔细想一想,可以用莫队解决。感觉这道题跟Gty的二逼妹子序列很像,都是要对权值进行分块。用t数组来判断是否这个块内用没出现过的数,感觉还不算太难。一开始想复杂了。

还有一点,本蒟蒻一开始写了离散化,但是后来膜了一下PoPoQQQ,发现其实答案不可能大于n,所以这道题就变得更简单了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
int l,r,id,s;
}q[200010];
int n,m;
int a[200010],belong[200010],bl[200010],br[200010],num[200010],t[200010];
void fk()
{
int cnt=sqrt(n);
for(int i=1;i<=n;i++)
{
int bg=(i-1)/cnt+1;
belong[i]=bg;
if(bl[bg]==0)bl[bg]=i,br[bg-1]=i-1;
}
br[belong
]=n;
}
bool cmp1(node a,node b)
{
if(belong[a.l]==belong[b.l])
{
if(a.r>b.r)return false;
if(a.r<b.r)return true;
return 0;
}
if(belong[a.l]>belong[b.l])return false;
if(belong[a.l]<belong[b.l])return true;
}
bool cmp2(node a,node b)
{
if(a.id>b.id)return false;
if(a.id<b.id)return true;
return 0;
}
void del(int x)
{
if(x>n)return ;
num[x]--;
if(num[x]==0)t[belong[x]]--;
}
void add(int x)
{
if(x>n)return ;
num[x]++;
if(num[x]==1)t[belong[x]]++;
}
int sle()
{
int ss;
if(num[0]==0)return 0;
for(int i=1;i<=belong
;i++)
{
if(t[i]<=br[i]-bl[i]){ss=i;break;}
}
for(int i=bl[ss];i<=br[ss];i++)
{
if(num[i]==0)return i;
}
return n;
}
void solve()
{
int l=1,r=0;
for(int i=1;i<=m;i++)
{
for(int j=q[i].r+1;j<=r;j++)del(a[j]);
for(int j=r+1;j<=q[i].r;j++)add(a[j]);
for(int j=l;j<=q[i].l-1;j++)del(a[j]);
for(int j=q[i].l;j<=l-1;j++)add(a[j]);
l=q[i].l,r=q[i].r;
q[i].s=sle();
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;
}
fk();
sort(q+1,q+m+1,cmp1);
solve();
sort(q+1,q+m+1,cmp2);
for(int i=1;i<=m;i++)printf("%d\n",q[i].s);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj 莫队 分块