天天看点

【YNOI2016】【BZOJ4939】【LOJ6199】【洛谷P4688】掉进兔子洞(莫队)(bitset)BZOJ传送门LOJ传送门洛谷传送门解析:

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;
}