BZOJ传送门
LOJ传送门
洛谷传送门
解析:
显然这个玩意不是什么鬼畜数据结构能够维护的,我们考虑暴力。
显然可以用离散化+bitset处理出每个区间的数出现情况。
由于一个数出现多次我们需要特殊处理,离散化后记录一个cnt,然后每次改变一个数的存在情况就在cnt+pos处将位取反。
显然这个过程可以用莫队来实现。
然后需要注意的就是,由于询问的存储空间开不下那么多bitset(也不可能开下),我们可以讲询问多分几次处理,我选择分5次。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc getchar
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=1e5+10;
int n;
int a[N],b[N],cnt[N],Ans[N/3];
std::bitset<N> s[N/3],R;
inline void ins(int val){
R[val+cnt[val]]=1;
++cnt[val];
}
inline void del(int val){
--cnt[val];
R[val+cnt[val]]=0;
}
int l,r;
int bsiz;
int block[N];
struct Query{
int l,r,id;
friend bool operator<(cs Query &a,cs Query &b){
return block[a.l]==block[b.l]?((block[a.l]&1)?(a.r>b.r):(a.r<b.r)):block[a.l]<block[b.l];
}
}q[N];
int qcnt;
inline void solve(int m){
qcnt=0;
for(int re i=0;i<m;++i){
s[i].set();Ans[i]=0;
q[qcnt].l=getint()-1,q[qcnt].r=getint()-1,q[qcnt].id=i;Ans[i]+=q[qcnt].r-q[qcnt].l+1;++qcnt;
q[qcnt].l=getint()-1,q[qcnt].r=getint()-1,q[qcnt].id=i;Ans[i]+=q[qcnt].r-q[qcnt].l+1;++qcnt;
q[qcnt].l=getint()-1,q[qcnt].r=getint()-1,q[qcnt].id=i;Ans[i]+=q[qcnt].r-q[qcnt].l+1;++qcnt;
}
std::sort(q,q+qcnt);
for(int re i=0;i<qcnt;++i){
while(q[i].l<l)ins(a[--l]);
while(q[i].r>r)ins(a[++r]);
while(q[i].l>l)del(a[l++]);
while(q[i].r<r)del(a[r--]);
s[q[i].id]&=R;
}
for(int re i=0;i<m;++i)std::cout<<Ans[i]-s[i].count()*3<<"\n";
}
signed main(){
l=0,r=-1;
std::ios::sync_with_stdio(false);
n=getint();int m=getint();
bsiz=std::max(1.,sqrt((double)n*n/m));
for(int re i=0;i<n;++i)block[i]=i/bsiz,a[i]=b[i]=getint();
std::sort(b,b+n);
for(int re i=0;i<n;++i)a[i]=std::lower_bound(b,b+n,a[i])-b;
solve(m/3);
solve((m+1)/3);
solve((m+2)/3);
return 0;
}