P4396 [AHOI2013] 作業
值域分塊入門題,其實和值域線段樹一樣道理,就是在值域上分塊。
發現有兩個限制:數列區間和值域區間,但是發現第二問很像求區間不同的數的個數,直接莫隊,但是我們還要對值域分塊,我們維護值域塊的某個數的出現次數以及塊內總和,然後查詢時就是普通的分塊區間和做法。
#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pir pair<int,int>
#define re register
const int inf=1e9;
const int N=4e5+10;
const int mod=1e9+7;
using namespace std;
int n,m;
int a[N];
int v;
struct ss{
int l,r,a,b,id;
}q[N];
int len,lenv;
int of[N],ofv[N];
int sum[N];//值域上單個數
int sumv[N];//值域塊內個數
int summ[N];//值域塊內不重複個數
void del(int x){
sum[a[x]]--;
sumv[ofv[a[x]]]--;
if(sum[a[x]]<=0){
summ[ofv[a[x]]]--;
}
}
void add(int x){
sum[a[x]]++;
sumv[ofv[a[x]]]++;
if(sum[a[x]]<=1){
summ[ofv[a[x]]]++;
}
}
int ans1[N],ans2[N];
int getans1(int a,int b){
int ans=0;
b=min(b,v);
if(a>v){
return 0;
}
if(ofv[a]==ofv[b]){
for(int i=a;i<=b;i++){
ans+=sum[i];
}
return ans;
}
for(int i=ofv[a]+1;i<=ofv[b]-1;i++){
ans+=sumv[i];
}
for(int i=a;ofv[i]==ofv[a]&&a<=v;i++){
ans+=sum[i];
}
for(int i=b;ofv[i]==ofv[b]&&b>=0;i--){
ans+=sum[i];
}
return ans;
}
int getans2(int a,int b){//不同個數
int ans=0;
b=min(b,v);
if(a>v){
return 0;
}
if(ofv[a]==ofv[b]){
for(int i=a;i<=b;i++){
ans+=(bool) sum[i];
}
return ans;
}
for(int i=ofv[a]+1;i<=ofv[b]-1;i++){
ans+=summ[i];
}
for(int i=a;ofv[i]==ofv[a]&&a<=v;i++){
ans+=(bool)sum[i];
}
for(int i=b;ofv[i]==ofv[b]&&b>=0;i--){
ans+=(bool)sum[i];
}
return ans;
}
bool cmp(ss g,ss h){
return (of[g.l]^of[h.l])?of[g.l]<of[h.l]:((of[g.l]&1)?g.r<h.r:g.r>h.r);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>m;
len=1.0*n/sqrt(m)+1;
for(int i=1;i<=n;i++){
cin>>a[i];
v=max(v,a[i]);
of[i]=(i-1)/len+1;
}
for(int i=1;i<=m;i++){
cin>>q[i].l>>q[i].r>>q[i].a>>q[i].b;
q[i].id=i;
}
lenv=1.0*sqrt(v)+1;
for(int i=1;i<=v;i++){
ofv[i]=(i-1)/lenv+1;
}
int l=1,r=0;
sort(q+1,q+1+m,cmp);
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--);
ans1[q[i].id]=getans1(q[i].a,q[i].b);
ans2[q[i].id]=getans2(q[i].a,q[i].b);
}
for(int i=1;i<=m;i++){
cout<<ans1[i]<<" "<<ans2[i]<<"\n";
}
return 0;
}