bzoj3920: Yuuna的禮物(莫隊+分塊套分塊)

  思路挺簡單的,可是總感受好難寫...碼力仍是差勁,最後寫出來也挺醜的ios

  這題顯然是個莫隊題,考慮怎麼轉移和詢問...ide

  根據莫隊修改多查詢少的特色,通常用修改快查詢慢的分塊來維護。查第$k_1$小的出現次數能夠用權值分塊作到$O(1)$修改,$O(\sqrt{n})$查詢,$k_2$小的數同理。對於每一種出現次數$i$,預處理出有幾種數在序列裏的出現次數$\geq i$,並在每種出現次數中對這些數離散化,這樣咱們就能對每種出現次數進行權值分塊查第$k_2$小的數了。spa

  由於$\sum cnt_i=n$,因此空間是$O(n)$的,這題卡空間...$O(n\sqrt{n})$的空間過不了....code

#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\n", ans[i]);
}
View Code
相關文章
相關標籤/搜索