bzoj3920: Yuuna的礼物(莫队+分块套分块)
2018-02-12 21:03
120 查看
思路挺简单的,但是总感觉好难写...码力还是差劲,最后写出来也挺丑的
这题显然是个莫队题,考虑怎么转移和询问...
根据莫队修改多查询少的特点,一般用修改快查询慢的分块来维护。查第$k_1$小的出现次数可以用权值分块做到$O(1)$修改,$O(\sqrt{n})$查询,$k_2$小的数同理。对于每一种出现次数$i$,预处理出有几种数在序列里的出现次数$\geq i$,并在每种出现次数中对这些数离散化,这样我们就能对每种出现次数进行权值分块查第$k_2$小的数了。
因为$\sum cnt_i=n$,所以空间是$O(n)$的,这题卡空间...$O(n\sqrt{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 ;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
相关文章推荐
- 【莫队算法】【权值分块】bzoj3920 Yuuna的礼物
- [BZOJ3920]Yuuna的礼物
- BZOJ.3920.Yuuna的礼物(莫队 分块套分块 分段离散化)
- bzoj 3920: Yuuna的礼物
- 给c++程序员的一份礼物——常用工具集
- 新年新礼物
- 天使的礼物
- Google对合作站点送礼物,居然是Google牌冰箱
- 送给程序员的节日礼物!
- 麦琪的礼物
- 51CTO两周岁生日礼物﹕三千万人次访问量 推荐
- 新年到了,祝大家新年快乐,礼物就送SSD1的部分答案哦
- 《兰岛物语:少女的约定》全后宫攻略补遗还有永恒的礼物简介和秘籍
- 收到的礼物——微软蓝牙无线鼠标5000
- [礼物]发布一款silverlight开发的相册
- 送给未来孩子的礼物
- 给软件技术学习者的礼物——《WCF概述》教学PPT及相关示例
- 一起来HAPPY,不得不送的礼物哦!
- 谁在圣诞节送礼物?
- 现身说法,如何给上司送礼物