题目大意
多次询问[l,r]内权值在[a,b]的数量及种类数。
分块
数量随便做,我们思考种类数怎么做。
具体见gty的二逼妹子序列题解
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,maxm=1000000+10;
struct dong{
int l,r,a,b,id;
};
int belong[maxn],a[maxn],ans1[maxm],ans[maxm],cnt[maxn],num[1000],sum[1000];
dong ask[maxm];
int i,j,k,l,r,t,n,m,c;
bool cmp(dong a,dong b){
if (belong[a.l]<belong[b.l]) return 1;
else if (belong[a.l]==belong[b.l]&&a.r<b.r) return 1;
else return 0;
}
void in(int x){
cnt[x]++;
sum[belong[x]]++;
if (cnt[x]==1) num[belong[x]]++;
}
void out(int x){
cnt[x]--;
sum[belong[x]]--;
if (cnt[x]==0) num[belong[x]]--;
}
int query(int j,int k){
int i,t=0;
int l=belong[j],r=belong[k];
if (r-l<=1){
fo(i,j,k)
if (cnt[i]>0) t++;
return t;
}
fo(i,l+1,r-1) t+=num[i];
fo(i,j,l*c)
if (cnt[i]>0) t++;
fo(i,(r-1)*c+1,k)
if (cnt[i]>0) t++;
return t;
}
int query2(int j,int k){
int i,t=0;
int l=belong[j],r=belong[k];
if (r-l<=1){
fo(i,j,k)
t+=cnt[i];
return t;
}
fo(i,l+1,r-1) t+=sum[i];
fo(i,j,l*c)
t+=cnt[i];
fo(i,(r-1)*c+1,k)
t+=cnt[i];
return t;
}
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int main(){
n=read(),m=read();
c=floor(sqrt(n));
fo(i,1,n) belong[i]=(i-1)/c+1;
fo(i,1,n) a[i]=read();
fo(i,1,m){
ask[i].l=read();ask[i].r=read();ask[i].a=read();ask[i].b=read();
ask[i].id=i;
}
sort(ask+1,ask+m+1,cmp);
l=r=1;
in(a[1]);
fo(i,1,m){
while (l<ask[i].l) out(a[l++]);
while (l>ask[i].l) in(a[--l]);
while (r<ask[i].r) in(a[++r]);
while (r>ask[i].r) out(a[r--]);
ans[ask[i].id]=query(ask[i].a,ask[i].b);
ans1[ask[i].id]=query2(ask[i].a,ask[i].b);
}
fo(i,1,m) printf("%d %d\n",ans1[i],ans[i]);
}