zoukankan      html  css  js  c++  java
  • [BZOJ3920]Yuuna的礼物

    题目大意:
      给你一个长度为$n(nle40000)$的数列${a_i}(1le a_ile n)$,给出$m(mle40000)$次询问,每次给出$l,r,k_1,k_2$询问区间$[l,r]$中出现次数第$k_1$小的数中第$k_2$小的数是多少?

    思路:
      运用莫队算法离线处理所有询问,分块维护数列中每个数的出现次数。考虑如何维护出现次数的出现次数以及出现次数相同的数。同样采用分块,先预处理出对于某一种出现次数,所有可能的数,再将其离散化,对于离散化后的数分块维护。由于题目空间限制只有24M,因此需要手写内存池或者使用vector,可以证明离散化以后的数组空间复杂度是$O(n)$的。这样时间复杂度$O(msqrt 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
    ",ans[i]);
    80     }
    81     return 0;
    82 }
  • 相关阅读:
    em与rem之间的区别以及移动设备中的rem适配方案
    关于两个DIV之间的空白字符
    Bootstrap基本模板
    js 裁剪
    记一次诡异的bug
    Node切换版本
    git 撤销
    使用 iframe + postMessage 实现跨域通信
    <el-input>标签限制输入小数点
    vue elementyUI table :点击一行时选中这一行对应的复选框
  • 原文地址:https://www.cnblogs.com/skylee03/p/8665974.html
Copyright © 2011-2022 走看看