[BZOJ3920]Yuuna的礼物
题目大意:
给你一个长度为$n(n\le40000)$的数列$\{a_i\}(1\le a_i\le n)$,给出$m(m\le40000)$次询问,每次给出$l,r,k_1,k_2$询问区间$[l,r]$中出现次数第$k_1$小的数中第$k_2$小的数是多少?
思路:
运用莫队算法离线处理所有询问,分块维护数列中每个数的出现次数。考虑如何维护出现次数的出现次数以及出现次数相同的数。同样采用分块,先预处理出对于某一种出现次数,所有可能的数,再将其离散化,对于离散化后的数分块维护。由于题目空间限制只有24M,因此需要手写内存池或者使用vector,可以证明离散化以后的数组空间复杂度是$O(n)$的。这样时间复杂度$O(m\sqrt n)$,空间复杂度是$O(n+m)$。
1 #include<cmath> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<algorithm> 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=40001,M=40000; 14 int n,a[N],b[N],block,ans[M],cnt[N]; 15 struct Query { 16 int l,r,k1,k2,id; 17 bool operator < (const Query &another) const { 18 return l/block<another.l/block||(l/block==another.l/block&&r<another.r); 19 } 20 }; 21 Query q[M]; 22 std::vector<int> v[N],rank[N],cnt1,sum1,cnt2[N],sum2[N]; 23 inline void modify(const int &x,const int &p,const int &d) { 24 cnt2[x][p]+=d; 25 sum2[x][p/block]+=d; 26 if(d==1&&!cnt1[x]++) sum1[x/block]++; 27 if(d==-1&&!--cnt1[x]) sum1[x/block]--; 28 } 29 inline void modify(const int &x,const int &d) { 30 if(cnt[x]) modify(cnt[x],rank[x][cnt[x]],-1); 31 if(cnt[x]+=d) modify(cnt[x],rank[x][cnt[x]],1); 32 } 33 inline int solve(const std::vector<int> &c,const std::vector<int> &s,const int &k) { 34 register int x=0,cnt=0; 35 while((cnt+s[x])<k) cnt+=s[x++]; 36 for(register int i=x*block;i<(x+1)*block;i++) { 37 if((cnt+=!!c[i])>=k) return i; 38 } 39 } 40 inline int query(const int &k1,const int &k2) { 41 const int x=solve(cnt1,sum1,k1); 42 return v[x][solve(cnt2[x],sum2[x],k2)]; 43 } 44 int main() { 45 block=sqrt(n=getint()); 46 for(register int i=1;i<=n;i++) { 47 cnt[a[i]=b[i]=getint()]++; 48 } 49 std::sort(&b[1],&b[n]+1); 50 for(register int i=1;i<=n;i++) { 51 if(b[i]==b[i-1]) continue; 52 rank[b[i]].resize(cnt[b[i]]+1); 53 for(register int j=1;j<=cnt[b[i]];j++) { 54 rank[b[i]][j]=v[j].size(); 55 v[j].push_back(b[i]); 56 } 57 cnt[b[i]]=0; 58 } 59 for(register int i=1;i<=n;i++) { 60 cnt2[i].resize(v[i].size()+1); 61 sum2[i].resize(cnt2[i].size()/block+1); 62 } 63 const int m=getint(); 64 for(register int i=0;i<m;i++) { 65 const int l=getint(),r=getint(),k1=getint(),k2=getint(); 66 q[i]=(Query){l,r,k1,k2,i}; 67 } 68 cnt1.resize(n+1); 69 sum1.resize(n/block+1); 70 std::sort(&q[0],&q[m]); 71 for(register int i=0,l=1,r=0;i<m;i++) { 72 while(r<q[i].r) modify(a[++r],1); 73 while(l>q[i].l) modify(a[--l],1); 74 while(r>q[i].r) modify(a[r--],-1); 75 while(l<q[i].l) modify(a[l++],-1); 76 ans[q[i].id]=query(q[i].k1,q[i].k2); 77 } 78 for(register int i=0;i<m;i++) { 79 printf("%d\n",ans[i]); 80 } 81 return 0; 82 }