传送门
题解:将权值进行分块,然后序列上进行莫队操作。查询时整块的就for块,块两边的for点。修改O(1),查询(√n)。
这种100sec的题跑久了无异于卡评测,所以建议使用读入优化,可以快接近1/3的时间
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int ,int >
#define mp(x,y) make_pair(x,y)
const int MAXN=1e6+2;
int n,m,siz,a[MAXN];
int bel[MAXN],cnt[MAXN],num[MAXN],blo[MAXN];
pii ans[MAXN];
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
struct Q {
int l,r,a,b,id;
friend bool operator <(const Q &x,const Q &y) {
return bel[x.l]^bel[y.l]?bel[x.l]<bel[y.l]:x.r<y.r;
}
}q[MAXN];
inline void update(int pos,int delta) {
int temp=a[pos];
cnt[temp]+=delta,num[bel[temp]]+=delta;
if (delta==-1&&!cnt[temp]) --blo[bel[temp]];
if (delta==1&&cnt[temp]==1) ++blo[bel[temp]];
}
pii query(int st,int ed) {
int fi=0,se=0;
if (bel[st]==bel[ed]) {//in the same block
for (int i=st;i<=ed;++i)
if (cnt[i]) fi+=cnt[i],++se;
}
else {//across a few blocks
for (int i=st;i<=bel[st]*siz;++i)
if (cnt[i]) fi+=cnt[i],++se;
for (int i=(bel[ed]-1)*siz+1;i<=ed;++i)
if (cnt[i]) fi+=cnt[i],++se;
for (int i=bel[st]+1;i<bel[ed];++i)
if (num[i]) fi+=num[i],se+=blo[i];
}
return mp(fi,se);
}
int main() {
// freopen("bzoj 3236.in","r",stdin);
n=read(),m=read(),siz=(int)sqrt((double)n);
for (register int i=1;i<=n;++i) a[i]=read(),bel[i]=(i-1)/siz+1;
for (register int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].a=read(),q[i].b=read(),q[i].id=i;
sort(q+1,q+m+1);
for (register int i=1,l=1,r=0;i<=m;++i) {
while (l<q[i].l) update(l++,-1);
while (r>q[i].r) update(r--,-1);
while (l>q[i].l) update(--l,1);
while (r<q[i].r) update(++r,1);
ans[q[i].id]=query(q[i].a,q[i].b);
}
for (register int i=1;i<=m;++i) printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}