luogu P4688 [Ynoi2016]掉进兔子洞
bitset优化莫队。
由于bitset并不能存可重集,所以我们考虑给每种元素在bitset里留 \(k\) 个位置(\(k\) 为这种元素的个数)。我们只需要在离散化的时候不去重,然后把 \(p\) 放进bitset中第 \(p-cnt_p\) 个位置就行了(\(cnt_p\) 为bitset当前存的 \(p\) 的个数)。
发现数组开不下,我们把询问分成三段处理就好。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<cmath>
using namespace std;
const int N=100009,M=34000;
int n,m,a[N],cnt=1,ans1[M],belong[M*3],block,b[N],sum[N];
bitset <N> now,ans[M];
struct Question
{
int l,r,id;
bool operator < (const Question A)const
{
if(belong[l]!=belong[A.l])
return l<A.l;
return (belong[l]&1)?r<A.r:r>A.r;
}
}q[M*3];
int read()
{
int x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
return x;
}
void init()
{
n=read(),m=read();
for (int i=1;i<=n;i++)
a[i]=b[i]=read();
sort(b+1,b+1+n);
for (int i=1;i<=n;i++)
a[i]=upper_bound(b+1,b+1+n,a[i])-b-1;
block=(int)sqrt(N);
for (int i=1;i<=(M-10)*3;i++)
belong[i]=(i-1)/block+1;
}
void add(int x)
{
now[x-sum[x]]=1;
sum[x]++;
}
void del(int x)
{
sum[x]--;
now[x-sum[x]]=0;
}
void work()
{
int tot=0,all=0;
memset(ans1,0,sizeof(ans1));
for (int i=1;i<=M-10&&cnt<=m;i++,cnt++,all++)
tot++,q[tot].l=read(),q[tot].r=read(),ans1[i]+=q[tot].r-q[tot].l+1,q[tot].id=i,
tot++,q[tot].l=read(),q[tot].r=read(),ans1[i]+=q[tot].r-q[tot].l+1,q[tot].id=i,
tot++,q[tot].l=read(),q[tot].r=read(),ans1[i]+=q[tot].r-q[tot].l+1,q[tot].id=i;
sort(q+1,q+1+tot);
memset(sum,0,sizeof(sum));
for (int i=1;i<=all;i++)
ans[i].set();
now.reset();
int l=1,r=0;
for (int i=1;i<=tot;i++)
{
while(r<q[i].r) add(a[++r]);
while(l>q[i].l) add(a[--l]);
while(r>q[i].r) del(a[r--]);
while(l<q[i].l) del(a[l++]);
ans[q[i].id]&=now;
}
for (int i=1;i<=all;i++)
printf("%d\n",ans1[i]-ans[i].count()*3);
if(cnt<=m)
work();
}
int main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!