洛谷 P4396 [AHOI2013]作业
题目描述
分析
因为询问是关于区间的,并且没有强制在线,所以能用莫队解决
但是还要支持查询区间内大于等于 \(a\),小于等于 \(b\) 的数的个数和数值的个数
所以还要套一个数据结构
比较好想的做法是对权值开一个数状数组
\(logn\) 修改,\(logn\) 查询
复杂度有点高
考虑莫队的本质是进行了 \(n\sqrt{m}\) 次修改和 \(m\) 次查询
我们的修改必须是 \(O(1)\) 的,但是查询的次数比较少,可以 \(O(\sqrt{n})\) 解决
所以可以用值域分块代替树状数组
代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
int n,m,a[maxn],blo,ans1[maxn],ans2[maxn],nans1,nans2,mmax,shuyu[maxn],cntcol[maxn],cntnum[maxn],cnt[maxn],lmax[maxn],rmax[maxn];
struct jie{
int l,r,jla,jlb,id;
jie(){}
jie(rg int aa,rg int bb,rg int cc,rg int dd,rg int ee){
l=aa,r=bb,jla=cc,jlb=dd,id=ee;
}
}b[maxn];
bool cmp(rg jie aa,rg jie bb){
if(shuyu[aa.l]==shuyu[bb.l]){
return shuyu[aa.l]&1?aa.r<bb.r:aa.r>bb.r;
} else {
return aa.l<bb.l;
}
}
void xg(rg int val,rg int op){
if(cnt[val]==0) cntcol[shuyu[val]]++;
cnt[val]+=op;
cntnum[shuyu[val]]+=op;
if(cnt[val]==0) cntcol[shuyu[val]]--;
}
void cx(rg int nl,rg int nr){
nans1=0,nans2=0;
for(rg int i=nl;i<=std::min(nr,rmax[shuyu[nl]]);i++){
nans1+=cnt[i];
nans2+=(cnt[i]!=0);
}
if(shuyu[nl]==shuyu[nr]) return;
for(rg int i=nr;i>=lmax[shuyu[nr]];i--){
nans1+=cnt[i];
nans2+=(cnt[i]!=0);
}
for(rg int i=shuyu[nl]+1;i<=shuyu[nr]-1;i++){
nans1+=cntnum[i];
nans2+=cntcol[i];
}
}
int main(){
memset(lmax,0x3f,sizeof(lmax));
n=read(),m=read();
for(rg int i=1;i<=n;i++) a[i]=read();
mmax=n;
rg int aa,bb,cc,dd;
for(rg int i=1;i<=m;i++){
aa=read(),bb=read(),cc=read(),dd=read();
mmax=std::max(mmax,bb);
b[i]=jie(aa,bb,cc,dd,i);
}
blo=sqrt(mmax);
for(rg int i=1;i<=mmax;i++){
shuyu[i]=(i-1)/blo+1;
lmax[shuyu[i]]=std::min(lmax[shuyu[i]],i);
rmax[shuyu[i]]=std::max(rmax[shuyu[i]],i);
}
std::sort(b+1,b+1+m,cmp);
rg int nl=1,nr=0;
for(rg int i=1;i<=m;i++){
while(nr<b[i].r) xg(a[++nr],1);
while(nl>b[i].l) xg(a[--nl],1);
while(nr>b[i].r) xg(a[nr--],-1);
while(nl<b[i].l) xg(a[nl++],-1);
cx(b[i].jla,b[i].jlb);
ans1[b[i].id]=nans1;
ans2[b[i].id]=nans2;
}
for(rg int i=1;i<=m;i++) printf("%d %d\n",ans1[i],ans2[i]);
return 0;
}