【算法一】

暴力。

可以通过第0、1号测试点。

预计得分:20分。

【算法二】

经典问题:区间众数,数据范围也不是很大,因此我们可以:

①分块,离散化,预处理出:

<1>前i块中x出现的次数(差分);

<2>第i块到第j块中的众数是谁,出现了多少次。

询问的时候,对于整块的部分直接获得答案;对于零散的部分,暴力统计每个数出现 的次数,加上差分的结果,尝试更新ans。

时间复杂度O(m*sqrt(n)),

空间复杂度O(n*sqrt(n))。

②考虑离线,莫队算法,转移的时候使用数据结构维护,具体实现不赘述。

时间复杂度O(m*sqrt(n)*log(n)),

空间复杂度O(n)。

结合算法一,预计得分:40分。

【算法三】

考虑离线,莫队算法,存储一个数组,记录权值的出现次数,然后我们把这些次数插 入到一个权值分块(即一种对权值分块的数据结构,特点是支持O(1)的插入删除和O(sqrt(n))的查询全局k大、全局排名、前驱、后继之类,因此可以良好地与莫队算法结合起来解决无修改的区间询问)里,如果仅仅需要知道众数出现的次数而已,我们就可以O(1)地实现转移,并且O(sqrt(n))地实现询问了。但是我们还需要知道k2小值,所以在权值分块的每个结点维护一棵平衡树,插入的时间复杂度就变高了。

时间复杂度O(m*sqrt(n)*log(n)(插入、删除)+m*sqrt(n)(查询))

空间复杂度O(n)。

可以通过0、1、2(?)、3(?)、4、5号测试点。

预计得分:40分~60分,结合算法二一定可以得到60分,可能需要常数优化。

【算法四】

我们发现算法三的主要问题在于插入到平衡树里是O(logn)的,因此如果我们把平衡树换成权值分块,就可以实现O(1)插入了,而且不会影响查询的复杂度。

但是,每个节点的子权值分块的大小是严格值域的,也就是说,出现次数可能为i的数都有可能在那个子权值分块里。这样我们的空间是无法承受的。因此,我们需要进行“分段离散化”(把对于一个出现次数i,要将出现次数>=i的权值全部离散掉。对每个i都得这样做)(复杂度在其后有证明)。

我们最终需要的数据结构是这样的:

一个数组Pinlv[],记录每种权值出现的次数;

一个权值分块block[],维护这些出现次数;

然后在以上那个权值分块的每个节点再开一个子权值分块,记录出现次数为其的权值是哪几种。

有点绕是不是……举个例子:

n=11

2 1 3 2 1 4 1 2 2 1 4

假设当前数据结构正在维护a1...an这个区间。

数组Pinlv

[1]

[2]

[3]

[4]

4

4

1

2

权值分块block

[1]

[2]

[3]

[4]

1

1

0

2

子权值分块

3

4

1

2

※一些复杂度的证明:

出现次数i

1

2

3

4

5

...

m

出现次数为i的权值的个数之和(含重复)

S1

S2

S3

S4

S5

...

Sm

S1+S2+S3+...+Sm=n(1<=m<=n)

Ai表示出现次数为i的权值种类数:

A1=S1

A2=S2/2

A3=S3/3

...

Am=Sm/m

设P是A的后缀和:

P1=A1+A2+A3+A4+...+Am

P2=A2+A3+A4...+Am

P3=A3+A4...+Am

...

Pm=Am

①子权值分块的总空间f:

f=P1+P2+...+Pm

=m*Am+(m-1)*Am-1+...+2*A2+1*A1

=m*Sm/m+(m-1)*Sm-1/m-1+...+1*S1/1

=S1+S2+S3+S4+...+Sm

=n

②不分段离散化的子权值分块的总空间f’:

f’=(A1+A2+...+Am)*n

复杂度难以保证。

③分段离散化的总时间复杂度g(这里涉及的log都是<=logn的,因此我们用logn代替):

先对原始数组去重,其大小就变成了A1+A2+...+Am

g<=P1*logn+P2*logn+...+Pm*logn

=(m*Am+(m-1)*Am-1+...+2*A2+1*A1)*logn

=(m*Sm/m+(m-1)*Sm-1/m-1+...+1*S1/1)*logn

=(S1+S2+S3+S4+...+Sm)*logn

=n*logn

④记录每种权值离散化后的值的数组的总空间h:

h=P1+P2+...+Pm

=m*Am+(m-1)*Am-1+...+2*A2+1*A1

=m*Sm/m+(m-1)*Sm-1/m-1+...+1*S1/1

=S1+S2+S3+S4+...+Sm

=n

因此,最终,只要合理地使用vector,我们的算法的空间复杂度便是O(n),

时间复杂度是O(m*sqrt(n))。

预计得分:100分。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<vector>
  6. using namespace std;
  7. #define MAXN 40001
  8. typedef vector<int>::iterator VER;
  9. int T[MAXN],plt;
  10. int n,m,a[MAXN],pl[MAXN],upd,num_mo[MAXN],anss[MAXN],num_pl[MAXN],l_pl[MAXN],s_pl[MAXN];
  11. vector<int>LiSan[MAXN],evpl[MAXN],evnum[MAXN],evl[MAXN],evs[MAXN],evb[MAXN];
  12. bool vis[MAXN];
  13. struct Ask{int l,r,k1,k2,p;}Q[MAXN];
  14. bool operator < (const Ask &a,const Ask &b)
  15. {return num_mo[a.l]!=num_mo[b.l] ? num_mo[a.l]<num_mo[b.l] : a.r<b.r;}
  16. void Mo_Make_Block()
  17. {
  18. int tot=1,sz=sqrt(n);
  19. if(!sz) sz=1;
  20. for(;tot*sz<n;++tot)
  21. {
  22. int r=tot*sz;
  23. for(int i=(tot-1)*sz+1;i<=r;++i)
  24. num_mo[i]=tot;
  25. }
  26. for(int i=(tot-1)*sz+1;i<=n;++i)
  27. num_mo[i]=tot;
  28. }
  29. void pl_Make_Block()
  30. {
  31. plt=1;
  32. int sz=sqrt(upd);
  33. if(!sz) sz=1;
  34. for(;plt*sz<upd;++plt)
  35. {
  36. l_pl[plt]=(plt-1)*sz+1;
  37. int r=plt*sz;
  38. for(int i=l_pl[plt];i<=r;++i)
  39. num_pl[i]=plt;
  40. }
  41. l_pl[plt]=(plt-1)*sz+1;
  42. for(int i=l_pl[plt];i<=upd;++i)
  43. num_pl[i]=plt;
  44. }
  45. void Insert(const int &x)
  46. {
  47. if(T[x])
  48. {
  49. --pl[T[x]];
  50. if(!pl[T[x]])--s_pl[num_pl[T[x]]];
  51. --evb[T[x]][LiSan[x][T[x]]];
  52. --evs[T[x]][evnum[T[x]][LiSan[x][T[x]]]];
  53. }
  54. ++T[x];
  55. if(!pl[T[x]])++s_pl[num_pl[T[x]]];
  56. ++pl[T[x]];
  57. ++evb[T[x]][LiSan[x][T[x]]];
  58. ++evs[T[x]][evnum[T[x]][LiSan[x][T[x]]]];
  59. }
  60. void Delete(const int &x)
  61. {
  62. --pl[T[x]];
  63. if(!pl[T[x]])--s_pl[num_pl[T[x]]];
  64. --evb[T[x]][LiSan[x][T[x]]];
  65. --evs[T[x]][evnum[T[x]][LiSan[x][T[x]]]];
  66. --T[x];
  67. if(T[x])
  68. {
  69. if(!pl[T[x]])++s_pl[num_pl[T[x]]];
  70. ++pl[T[x]];
  71. ++evb[T[x]][LiSan[x][T[x]]];
  72. ++evs[T[x]][evnum[T[x]][LiSan[x][T[x]]]];
  73. }
  74. }
  75. int Query(const int &K1,const int &K2)
  76. {
  77. int cnt1=0,cnt2=0;
  78. for(int i=1;;++i)
  79. {
  80. cnt1+=s_pl[i];
  81. if(cnt1>=K1)
  82. {
  83. cnt1-=s_pl[i];
  84. for(int j=l_pl[i];;++j)
  85. {
  86. cnt1+=(bool)pl[j];
  87. if(cnt1>=K1)
  88. {
  89. for(int k=1;;++k)
  90. {
  91. cnt2+=evs[j][k];
  92. if(cnt2>=K2)
  93. {
  94. cnt2-=evs[j][k];
  95. for(int l=evl[j][k];;++l)
  96. {
  97. cnt2+=evb[j][l];
  98. if(cnt2>=K2)
  99. return evpl[j][l];
  100. }
  101. }
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108. int main()
  109. {
  110. scanf("%d",&n);
  111. Mo_Make_Block();
  112. for(int i=1;i<=n;++i)
  113. {
  114. scanf("%d",&a[i]);
  115. ++pl[a[i]];
  116. }
  117. upd=*max_element(pl+1,pl+n+1);
  118. pl_Make_Block();
  119. for(int i=1;i<=n;++i)
  120. if(!vis[a[i]])
  121. {
  122. vis[a[i]]=1;
  123. LiSan[a[i]].assign(pl[a[i]]+1,0);
  124. for(int j=1;j<=pl[a[i]];++j)
  125. evpl[j].push_back(a[i]);
  126. }
  127. for(int i=1;i<=upd;++i)
  128. {
  129. //分段离散化
  130. sort(evpl[i].begin(),evpl[i].end());
  131. int k=1;
  132. for(VER j=evpl[i].begin();j!=evpl[i].end();++j,++k)
  133. LiSan[*j][i]=k;
  134. //分段权值分块
  135. int Lim=evpl[i].size();
  136. evb[i].assign(Lim+1,0);
  137. int tot=1,sz=sqrt(Lim);
  138. evl[i].push_back(0);
  139. evnum[i].push_back(0);
  140. if(!sz) sz=1;
  141. for(;tot*sz<Lim;++tot)
  142. {
  143. evl[i].push_back((tot-1)*sz+1);
  144. int r=tot*sz;
  145. for(int j=evl[i][tot];j<=r;++j)
  146. evnum[i].push_back(tot);
  147. }
  148. evl[i].push_back((tot-1)*sz+1);
  149. for(int j=evl[i][tot];j<=Lim;++j)
  150. evnum[i].push_back(tot);
  151. evs[i].assign(tot+1,0);
  152. evpl[i].insert(evpl[i].begin(),0);
  153. }
  154. scanf("%d",&m);
  155. for(int i=1;i<=m;++i)
  156. {
  157. scanf("%d%d%d%d",&Q[i].l,&Q[i].r,&Q[i].k1,&Q[i].k2);
  158. Q[i].p=i;
  159. }
  160. sort(Q+1,Q+m+1);
  161. memset(pl,0,(n+1)*sizeof(int));
  162. for(int i=Q[1].l;i<=Q[1].r;++i)
  163. Insert(a[i]);
  164. anss[Q[1].p]=Query(Q[1].k1,Q[1].k2);
  165. for(int i=2;i<=m;++i)
  166. {
  167. if(Q[i].l<Q[i-1].l)
  168. for(int j=Q[i-1].l-1;j>=Q[i].l;--j)
  169. Insert(a[j]);
  170. if(Q[i].r>Q[i-1].r)
  171. for(int j=Q[i-1].r+1;j<=Q[i].r;++j)
  172. Insert(a[j]);
  173. if(Q[i].l>Q[i-1].l)
  174. for(int j=Q[i-1].l;j<Q[i].l;++j)
  175. Delete(a[j]);
  176. if(Q[i].r<Q[i-1].r)
  177. for(int j=Q[i-1].r;j>Q[i].r;--j)
  178. Delete(a[j]);
  179. anss[Q[i].p]=Query(Q[i].k1,Q[i].k2);
  180. }
  181. for(int i=1;i<=m;++i)
  182. printf("%d\n",anss[i]);
  183. return 0;
  184. }

【莫队算法】【权值分块】bzoj3920 Yuuna的礼物的更多相关文章

  1. BZOJ2038: [2009国家集训队]小Z的袜子(hose) -- 莫队算法 ,,分块

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 3577  Solved: 1652[Subm ...

  2. 莫队算法 sqrt(n)分块思想

    在此说一下本渣对莫队算法思想的一些浅薄理解 莫队算法的思想就是对真个区间的分块,然后按照每块来分别进行计算,这样最终的复杂度可以达到n*sqrt(n) 小Z的袜子是一道非常经典的题目.:题目链接htt ...

  3. Luogu 1494 - 小Z的袜子 - [莫队算法模板题][分块]

    题目链接:https://www.luogu.org/problemnew/show/P1494 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天 ...

  4. 莫队或权值线段树 或主席树 p4137

    题目描述 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 输入格式 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问l,r. 输出格式 ...

  5. 【BZOJ】4358: permu 莫队算法

    [题意]给定长度为n的排列,m次询问区间[L,R]的最长连续值域.n<=50000. [算法]莫队算法 [题解]考虑莫队维护增加一个数的信息:设up[x]表示数值x往上延伸的最大长度,down[ ...

  6. 【莫队算法】【权值分块】poj2104 K-th Number / poj2761 Feed the dogs

    先用莫队算法保证在询问之间转移的复杂度,每次转移都需要进行O(sqrt(m))次插入和删除,权值分块的插入/删除是O(1)的. 然后询问的时候用权值分块查询区间k小值,每次是O(sqrt(n))的. ...

  7. 【莫队算法】【权值分块】bzoj2223 [Coci 2009]PATULJCI

    不带修改主席树裸题<=>莫队+权值分块裸题. 复杂度O(m*sqrt(n)). P.S.题目描述坑爹,第二个数是权值的范围. #include<cstdio> #include ...

  8. 【DFS序】【莫队算法】【权值分块】bzoj2809 [Apio2012]dispatching

    题意:在树中找到一个点i,并且找到这个点子树中的一些点组成一个集合,使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大 首先,我们将树处理出dfs序,将子树询问转化成区间询问. 然后我们 ...

  9. 【莫队算法】【权值分块】bzoj3585 mex

    orz PoPoQQQ. 本来蒟蒻以为这种离散化以后就对应不起来的题不能权值分块搞的说. ……结果,实际上>n的权值不会对答案作出贡献. #include<cstdio> #incl ...

随机推荐

  1. SHELL (2) —— Shell变量的核心基础知识和实践

    摘自:Oldboy Linux运维——SHELL编程实战 Shell变量:用一个固定的字符串(也可能是字符.数字等的组合)代替更多.更复杂的内容,该内容里可能还会包含变量.路径.字符串等其它的内容. ...

  2. [转载]Supporting OData $inlinecount with the new Web API OData preview package

    http://www.strathweb.com/2012/08/supporting-odata-inlinecount-with-the-new-web-api-odata-preview-pac ...

  3. shape-outside 矩形之外的另一种思路

    http://docs.webplatform.org/wiki/css/properties/shape-outside

  4. bash脚本:集群资源争夺战crazy-killer

    背景 公司的集群很多人一起用,有时候就难免资源紧张,某次需要用的时候没资源等了半天还是没资源,再等半天还是没资源,于是就写了个脚本泄愤,建议看到的人拷走放在自己公司集群上长期运行 :) 实现 此脚本运 ...

  5. [转]C++11 随机数学习

    相对于C++ 11之前的随机数生成器来说,C++11的随机数生成器是复杂了很多.这是因为相对于之前的只需srand.rand这两函数即可获取随机数来说,C++11提供了太多的选择和东西. 随机数生成算 ...

  6. vs-code 配置

    vs-code 快键键 命令面板 ctrl+shift+p vs-code 相关插件 AutoFileName Chinese (Simplified) Language Pack for Visua ...

  7. arm GIC介绍之四【转】

    转自:https://blog.csdn.net/sunsissy/article/details/73882718 GIC是ARM体系中重要的组件,在认识到GIC的组成和功能之后,了解到IRQ的大致 ...

  8. css-实现图标在输入框中显示

    一:JavaScript 是脚本语言 JavaScript 是一种轻量级的编程语言. JavaScript 是可插入 HTML 页面的编程代码. JavaScript 插入 HTML 页面后,可由所有 ...

  9. Android 常用动画之RotateAnimation

    前两天接到任务做一个UI,有用到动画,于是抽空看了下Android动画相关知识. Android Animation共有四大类型,分别是 Alpha      透明度动画 Scale      大小伸 ...

  10. tensorflow中的kernel/Adam 变量的来源

    原因是使用Adam优化函数时,Adam函数会创建一个Adam变量,目的是保存你使用tensorflow创建的graph中的每个可训练参数的动量, words/_word_embeddings:0 bi ...