[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 }

 

posted @ 2018-03-28 20:07  skylee03  阅读(241)  评论(0编辑  收藏  举报