【题解】[AHOI2013]作业

Link

题目大意:\(n\)个数,\(m\)个询问,每次四个参数,\(l,r,a,b\),问区间\([l,r]\)中出现过的,数值在\([a,b]\)区间中的数的个数以及区间\([l,r]\)中数值在\([a,b]\)中的数的个数。

注意理解 这两个是不一样的。

\(\text{Solution:}\)

观察到区间颜色出现次数可以想到莫队。

由于多了一个限制,那么我们考虑如何更新答案,并利用前缀思想:

指针移动的时候,维护颜色数以及这个颜色的值,对应在一个树状数组上更新。注意维护两个树状数组,分别处理两个询问。其他的和普通莫队没什么区别。

复杂度\(O(n\sqrt{n}\log n).\)此处替换\(m\)因为它们同阶。

其实还有莫队套分块的更优复杂度以及\(KDT,cdq\)分治等多种做法,在此不做赘述。

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
const int MAXN=1e6+10;
int col[MAXN],cnt[MAXN],a[MAXN],n,m,tr[MAXN];
int bl[MAXN],siz,bnum,now,tr1[MAXN];
pair<int,int>ans[MAXN];
inline bool R(char C){return C>='0'&&C<='9';}
inline int read(){
	int s=0;
	char ch=getchar();
	while(!R(ch))ch=getchar();
	while(R(ch))s=s*10+ch-48,ch=getchar();
	return s;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>=10)write(x/10);
	putchar(x%10+48);
}
struct Q{
	int l,r,a,b,id;
}q[MAXN];
inline bool cmp(Q a,Q b){return (bl[a.l]^bl[b.l])?bl[a.l]<bl[b.l]:(bl[a.l]&1)?a.r<b.r:a.r>b.r;}
inline void change(int x,int v){for(;x<=n;x+=lowbit(x))tr[x]+=v;}
inline int sum(int x){int res=0;for(;x;x-=lowbit(x))res+=tr[x];return res;}
inline void change2(int x,int v){for(;x<=n;x+=lowbit(x))tr1[x]+=v;}
inline int sum2(int x){int res=0;for(;x;x-=lowbit(x))res+=tr1[x];return res;}

inline void del(int x){
	--cnt[a[x]];
	if(!cnt[a[x]])now--,change(a[x],-1);
	change2(a[x],-1);
}
inline void add(int x){
	if(!cnt[a[x]])change(a[x],1),now++;
	++cnt[a[x]];change2(a[x],1);
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i)a[i]=read();
	siz=sqrt(n);bnum=ceil((double)n/siz);
	for(int i=1;i<=bnum;++i)for(int j=(i-1)*siz+1;j<=i*siz;++j)bl[j]=i;
	for(int i=1;i<=m;++i){
		q[i].id=i;
		q[i].l=read();
		q[i].r=read();
		q[i].a=read();
		q[i].b=read();
	}
	sort(q+1,q+m+1,cmp);
	int l=1,r=0;
	for(int i=1;i<=m;++i){
		int ql=q[i].l,qr=q[i].r;
		while(l<ql)del(l++);
		while(l>ql)add(--l);
		while(r<qr)add(++r);
		while(r>qr)del(r--);
		ans[q[i].id].first=sum2(q[i].b)-sum2(q[i].a-1);
		ans[q[i].id].second=sum(q[i].b)-sum(q[i].a-1);
	}
	for(int i=1;i<=m;++i)write(ans[i].first),putchar(' '),write(ans[i].second),putchar('\n');
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/h-lka/p/12944679.html