【题解】洛谷:P4396 [AHOI2013] 作业
P4396 [AHOI2013] 作业
值域分块入门题,其实和值域线段树一样道理,就是在值域上分块。
发现有两个限制:数列区间和值域区间,但是发现第二问很像求区间不同的数的个数,直接莫队,但是我们还要对值域分块,我们维护值域块的某个数的出现次数以及块内总和,然后查询时就是普通的分块区间和做法。
后记:
在区间 \([l,r]\) 中,在值域为 \([a,b]\),中不同的数的个数(\(pre[i]\)),裸的三维数点问题,可以用树套数或 cdq。
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步