zoukankan      html  css  js  c++  java
  • bzoj3920: Yuuna的礼物(莫队+分块套分块)

      思路挺简单的,但是总感觉好难写...码力还是差劲,最后写出来也挺丑的

      这题显然是个莫队题,考虑怎么转移和询问...

      根据莫队修改多查询少的特点,一般用修改快查询慢的分块来维护。查第$k_1$小的出现次数可以用权值分块做到$O(1)$修改,$O(sqrt{n})$查询,$k_2$小的数同理。对于每一种出现次数$i$,预处理出有几种数在序列里的出现次数$geq i$,并在每种出现次数中对这些数离散化,这样我们就能对每种出现次数进行权值分块查第$k_2$小的数了。

      因为$sum cnt_i=n$,所以空间是$O(n)$的,这题卡空间...$O(nsqrt{n})$的空间过不了....

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=40010, inf=1e9, sqrtm=210;
    struct poi{int l, r, k1, k2, pos;}q[maxn];
    int n, m, x, blo;
    vector<int>v[maxn], v2[maxn], sum2[maxn], blsum2[maxn];
    int sum1[maxn], blsum1[sqrtm], a[maxn], b[maxn], bl[maxn], cnt[maxn], ans[maxn];
    inline void read(int &k)
    {
        int f=1; k=0; char c=getchar();
        while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar();
        while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
        k*=f;    
    } 
    bool operator < (poi a, poi b)
    {return bl[a.l]<bl[b.l] || (bl[a.l]==bl[b.l] && ((bl[a.l]&1)?a.r<b.r:a.r>b.r));} 
    inline void add(int x, int delta)
    {
        x=a[x]; int pos=v2[x][cnt[x]-1];
        sum1[cnt[x]]+=delta;
        if(sum1[cnt[x]]==1 && delta==1) blsum1[bl[cnt[x]]]++;
        if(sum1[cnt[x]]==0 && delta==-1) blsum1[bl[cnt[x]]]--;
        sum2[cnt[x]][pos]+=delta; 
        blsum2[cnt[x]][bl[pos]]+=delta;
    }
    inline void update(int x, int delta)
    {
        if(cnt[a[x]]>0) add(x, -1); 
        cnt[a[x]]+=delta; 
        if(cnt[a[x]]>0) add(x, 1);
    }
    inline int query1(int k)
    {
        int x=0, cnt=0;
        for(int i=1;i<=bl[n];i++)
        if(cnt+blsum1[i]>=k) break;
        else cnt+=blsum1[i], x++;
        for(int i=blo*x;i<=min(n, blo*(x+1));i++)
        if(cnt+(sum1[i]!=0)>=k) return i;
        else cnt+=(sum1[i]!=0);
        return 0;
    }
    inline int query2(int ty, int k)
    {
        int x=0, cntt=0;
        for(int i=1;i<blsum2[ty].size();i++)
        if(cntt+blsum2[ty][i]>=k) break;
        else cntt+=blsum2[ty][i], x++;
        for(int i=blo*x;i<=min(n, blo*(x+1));i++)
        {
            if(cntt+sum2[ty][i]>=k) return i;
            else cntt+=sum2[ty][i];
        }
        return 0;
    }
    int main()
    {
        read(n); blo=sqrt(n); for(int i=0;i<=n;i++) bl[i]=i/blo+1;
        for(int i=1;i<=n;i++) read(a[i]), b[i]=a[i];
        sort(b+1, b+1+n); for(int i=1;i<=n;i++) cnt[b[i]]++;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=cnt[b[i]];j++) 
            {
                v2[b[i]].push_back(v[j].size());
                v[j].push_back(b[i]);
                sum2[j].push_back(0);
            }
            cnt[b[i]]=0;
        }
        for(int i=1;i<=n;i++)
        for(int j=0;j<=bl[sum2[i].size()];j++) 
        blsum2[i].push_back(0);
        read(m);
        for(int i=1;i<=m;i++) 
        read(q[i].l), read(q[i].r), read(q[i].k1), read(q[i].k2), q[i].pos=i;
        sort(q+1, q+1+m);
        for(int i=1, l=1, r=0;i<=m;i++)
        {
            while(l<q[i].l) update(l++, -1);
            while(l>q[i].l) update(--l, 1);
            while(r<q[i].r) update(++r, 1);
            while(r>q[i].r) update(r--, -1);
            x=query1(q[i].k1);
            ans[q[i].pos]=v[x][query2(x, q[i].k2)];
        }
        for(int i=1;i<=m;i++) printf("%d
    ", ans[i]);
    }
    View Code
  • 相关阅读:
    时间控件的操作
    Appium环境搭建
    测试常用英文词汇
    自动化测试中一段代码对应多个用例
    Linux常见命令
    元素的操作的简谈
    eclipse代码编辑界面代码块收缩的实现
    关键字驱动和数据驱动
    uni-app中如何判断浏览器内核
    JS实现 图片放大镜功能
  • 原文地址:https://www.cnblogs.com/Sakits/p/8445534.html
Copyright © 2011-2022 走看看