BZOJ.3920.Yuuna的礼物(莫队 分块套分块 分段离散化)
2018-02-20 21:49
295 查看
题目链接
详细题解:https://www.cnblogs.com/autsky-jadek/p/4376091.html
代码参考自:https://www.cnblogs.com/Sakits/p/8445534.html
思路好理解,然而就是写了一下午+一晚上。。
但是还需要知道第k2小的值,可以每个块维护点的个数棵平衡树,但这样插入复杂度会变高
同样可以在每个块内每个节点再套一个权值分块,同样能够\(O(1)\)插入
但是权值分块的大小是严格值域的,即出现次数为i的值都可能出现在i块里,这样空间无法承受
于是需要分段离散化,对于块i,用出现次数\(>=i\)的\(A_x\)对其离散化。
\(∑tm_i=n\),所以空间是\(O(n)\)的;时间复杂度\(O(m*sqrt(n))\)(证明见上博客 )
详细题解:https://www.cnblogs.com/autsky-jadek/p/4376091.html
代码参考自:https://www.cnblogs.com/Sakits/p/8445534.html
思路好理解,然而就是写了一下午+一晚上。。
\(Description\)
给定一个长为n的序列,每次查询区间中出现次数k1小的数里面的k2小的数。卡空间。\(Solution\)
将出现次数按权值分块,这样可以实现\(O(1)\)插入,\(O(sqrt(n))\)查询第k1小的出现次数但是还需要知道第k2小的值,可以每个块维护点的个数棵平衡树,但这样插入复杂度会变高
同样可以在每个块内每个节点再套一个权值分块,同样能够\(O(1)\)插入
但是权值分块的大小是严格值域的,即出现次数为i的值都可能出现在i块里,这样空间无法承受
于是需要分段离散化,对于块i,用出现次数\(>=i\)的\(A_x\)对其离散化。
\(∑tm_i=n\),所以空间是\(O(n)\)的;时间复杂度\(O(m*sqrt(n))\)(证明见上博客 )
//细节。。 #include <cmath> #include <cstdio> #include <cctype> #include <vector> #include <algorithm> #define gc() getchar() #define pb push_back typedef unsigned short ushort; const int N=40005; ushort n,size,m,A ,B ,bel ,Ans ; int sz1 ,sum1 ,tm ;//都可能有负 std::vector<ushort> sum2 /*某块中存在某数*/,ref ,rank /*某个数在某块中的位置*/,sz2 ; struct Ask { int l,r,k1,k2,id; bool operator <(const Ask &a)const { return bel[l]==bel[a.l]? r<a.r : bel[l]<bel[a.l]; // return bel[l]==bel[a.l]? ((l-1)/size&1 ? r>a.r : r<a.r) : bel[l]<bel[a.l]; } }q ; inline ushort read() { ushort now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } int Get_Pos1(int p)//找到k1所在大块、and 具体的套着的那个块 { int x=1; for(int i=1; i<=bel ; ++i) if((p-=sz1[i])<=0) {p+=sz1[x=i]; break;} for(int tmp=std::min((int)n,x*size-1),i=(x-1)*size; i<=tmp; ++i) if(!(p-=(sum1[i]>0))) return i; } int Get_Pos2(int id,int p) { int x=1; for(int i=1; i<sum2[id].size(); ++i)//不能是<bel[sum2[id].size()],不如直接<size,反正它肯定会结束 if((p-=sz2[id][i])<=0) {p+=sz2[id][x=i]; break;} for(int tmp=std::min((int)sum2[id].size(),x*size),i=(x-1)*size; i<tmp; ++i)//注意vector的边界 if(!(p-=sum2[id][i])) return i; } int Query(int k1,int k2) { int id=Get_Pos1(k1); return ref[id][Get_Pos2(id,k2)]; } inline void Update(int p,int delta)//仅在tm[p]>0(不是if(tm[p]))时加! {//修改块内的块 sum1[tm[p]]+=delta;//同理 这个也要减掉 if(sum1[tm[p]] && delta==1) ++sz1[bel[tm[p]]]; if(!sum1[tm[p]] && delta==-1) --sz1[bel[tm[p]]]; int pos=rank[p][tm[p]-1];//对于相同数多次出现已是位于不同的块,so 出现次数就不用管了 sz2[tm[p]][bel[pos]]+=delta, sum2[tm[p]][pos]+=delta; } inline void Modify(int p,int delta) { if(tm[p]>0) Update(p,-1);//要把原先的次数删掉 tm[p]+=delta; if(tm[p]>0) Update(p,1); } //inline void Add(int p)//WA: 没有把之前的sz1减掉 //{ // if(tm[p]>0) Update(p,-1);//要把原先的次数删掉 // ++tm[p]; // if(++sum1[tm[p]]==1) ++sz1[bel[tm[p]]];//对于外面的块 每个出现次数只计算一次 // if(tm[p]>0) Update(p,1); //} //inline void Subd(int p) //{ // if(tm[p]>0) Update(p,-1); // if(!--sum1[tm[p]]) --sz1[bel[tm[p]]]; // if(--tm[p]>0) Update(p,1);//次数-1后的加上 //} int main() { n=read(), size=sqrt(n); bel[0]=1;//得有bel[0]给vector使 for(int i=1; i<=n; ++i) A[i]=B[i]=read(),++tm[A[i]],bel[i]=i/size+1;//全从0开始分块更方便 std::sort(B+1,B+1+n); for(int i=1; i<=n; ++i)//Discrete { for(int j=1; j<=tm[B[i]]; ++j) sum2[j].pb(0), rank[B[i]].pb(ref[j].size()), ref[j].pb(B[i]); tm[B[i]]=0;//去重 } for(int i=1; i<=n; ++i) for(int j=0; j<=bel[sum2[i].size()]; ++j) sz2[i].pb(0);//<=! m=read(); for(int i=1; i<=m; ++i) q[i].l=read(),q[i].r=read(),q[i].k1=read(),q[i].k2=read(),q[i].id=i; std::sort(q+1,q+1+m); for(int l=1,r=0,i=1; i<=m; ++i) { while(l<q[i].l) Modify(A[l++],-1); while(l>q[i].l) Modify(A[--l],1); while(r<q[i].r) Modify(A[++r],1); while(r>q[i].r) Modify(A[r--],-1); Ans[q[i].id]=Query(q[i].k1,q[i].k2); } for(int i=1; i<=m; ++i) printf("%d\n",Ans[i]); return 0; }
相关文章推荐
- 【莫队算法】【权值分块】bzoj3920 Yuuna的礼物
- Bzoj 3289: Mato的文件管理 莫队,树状数组,逆序对,离散化,分块
- bzoj 3781: 小B的询问 莫队算法+分块
- 【BZOJ3809】Gty的二逼妹子序列【莫队算法】【分块】
- BZOJ-3757 苹果树 LCA 莫队算法 树分块
- Bzoj 3781: 小B的询问 莫队,分块,暴力
- [bzoj 3809] Gty的二逼妹子序列 莫队+分块
- 【莫队算法】【权值分块】bzoj3809 Gty的二逼妹子序列
- 【bzoj3809】【GTY的二逼妹子序列】【莫队+分块】
- bzoj 3809(莫队+分块求和)
- 【BZOJ3809/3236】Gty的二逼妹子序列 [Ahoi2013]作业 莫队算法+分块
- bzoj 4129: Haruna’s Breakfast 树上带修改莫队+分块
- BZOJ 3809 Gty的二逼妹子序列 | 莫队 + 分块
- 【bzoj3809】Gty的二逼妹子序列 莫队+分块
- Bzoj 2120: 数颜色 && 2453: 维护队列 莫队,分块,bitset
- 【bzoj4129】Haruna’s Breakfast 带修改树上莫队+分块
- BZOJ 3585 mex 莫队算法+分块
- 【BZOJ 2038】小Z的袜子【莫队+分块裸题】
- BZOJ3236: [Ahoi2013]作业 莫队+分块
- Bzoj 3236: [Ahoi2013]作业 莫队,分块