分块神题。

看了一会儿题解,看懂了思路,然后写了两个小时,调了一个多小时,好多地方写错了。

我们考虑对序列和值域都分块。\(sum1[i][j]\) 表示前 \(i\) 个块,第 \(j\) 块值域有几个数,\(sum2[i][j]\) 表示前 \(i\) 个块,值为 \(j\) 有几个数,\(id[i][j]\) 表示第 \(i\) 块值为 \(j\) 的编号,\(mp[i][j]\) 表示第 \(i\) 块编号为 \(j\) 值为多少,这样空间正好开的下。

对于修改操作,我们考虑边角暴力。在整块中若只有 \(x\) 那么直接修改,若又有 \(y\) 的话就暴力重构。每次重构整块中不同的数的数目会 \(-1\),一个块最多被重构 \(\sqrt{n}\) 块,所以时间复杂度保证为 \(O(n\sqrt{n})\)

对于询问操作,我们利用 \(sum1\) 和 \(sum2\) 可以在 \(O(\sqrt{n})\) 得到。

时间复杂度 \(O(n\sqrt{n})\),空间复杂度 \(O(n\sqrt{n})\)

洛谷加了 \(fread,fwrite\) 才卡过去,空间差点 \(MLE\)。。。

\(Code\ Below:\)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=100000+10;
  4. const int maxblo=317;
  5. const int lim=100000;
  6. int n,m,blo,a[maxn],pos[maxn],bl[maxn],L[maxn],R[maxn];
  7. int v1[maxn],v2[maxn],sum1[maxblo][maxblo],sum2[maxblo][maxn],id[maxblo][maxn],mp[maxblo][maxblo];
  8. namespace FastIO{
  9. #define gc() (iS==iT?(iT=(iS=ibuff)+fread(ibuff,1,SIZ,stdin),(iS==iT?EOF:*iS++)):*iS++)
  10. const int SIZ=1<<21|1;
  11. char *iS,*iT,ibuff[SIZ],obuff[SIZ],*oS=obuff,*oT=oS+SIZ-1,fu[110],c;int fr;
  12. inline void out(){
  13. fwrite(obuff,1,oS-obuff,stdout);
  14. oS=obuff;
  15. }
  16. template <class T>
  17. inline void read(T &x){
  18. x=0;T y=1;
  19. for(c=gc();(c>'9'||c<'0')&&c!='-';c=gc());
  20. c=='-'?y=-1:x=(c&15);
  21. for(c=gc();c>='0'&&c<='9';c=gc()) x=x*10+(c&15);
  22. x*=y;
  23. }
  24. template <class T>
  25. inline void print(T x,char text='\n'){
  26. if(x<0) *oS++='-',x*=-1;
  27. if(x==0) *oS++='0';
  28. while(x) fu[++fr]=x%10+'0',x/=10;
  29. while(fr) *oS++=fu[fr--];
  30. *oS++=text;out();
  31. }
  32. }
  33. using namespace FastIO;
  34. inline void reset(int x){
  35. for(int i=L[x];i<=R[x];i++) a[i]=mp[x][pos[i]];
  36. }
  37. inline void change(int bel,int x,int y){
  38. int last=id[bel][x];id[bel][y]=last;
  39. mp[bel][last]=y;id[bel][x]=0;
  40. }
  41. inline void build(int x){
  42. for(int i=1;i<=blo;i++) id[x][mp[x][i]]=0;
  43. int ind=0;
  44. for(int i=L[x];i<=R[x];i++)
  45. if(!id[x][a[i]]) id[x][a[i]]=++ind,mp[x][ind]=a[i];
  46. for(int i=L[x];i<=R[x];i++) pos[i]=id[x][a[i]];
  47. }
  48. inline void rebuild(int l,int x,int y){
  49. for(int i=bl[l];i<=bl[n];i++){
  50. sum1[i][bl[x]]+=sum1[i-1][bl[x]];
  51. sum1[i][bl[y]]+=sum1[i-1][bl[y]];
  52. sum2[i][x]+=sum2[i-1][x];
  53. sum2[i][y]+=sum2[i-1][y];
  54. }
  55. }
  56. inline void modify(int l,int r,int x,int y){
  57. if(sum2[bl[r]][x]==sum2[bl[l]-1][x]) return ;
  58. for(int i=bl[n];i>=bl[l];i--){
  59. sum1[i][bl[x]]-=sum1[i-1][bl[x]];
  60. sum1[i][bl[y]]-=sum1[i-1][bl[y]];
  61. sum2[i][x]-=sum2[i-1][x];
  62. sum2[i][y]-=sum2[i-1][y];
  63. }
  64. if(bl[l]==bl[r]){
  65. reset(bl[l]);
  66. for(int i=l;i<=r;i++)
  67. if(a[i]==x){
  68. a[i]=y;
  69. sum1[bl[l]][bl[x]]--;
  70. sum1[bl[l]][bl[y]]++;
  71. sum2[bl[l]][x]--;
  72. sum2[bl[l]][y]++;
  73. }
  74. build(bl[l]);rebuild(l,x,y);
  75. return ;
  76. }
  77. reset(bl[l]);reset(bl[r]);
  78. for(int i=l;i<=R[bl[l]];i++)
  79. if(a[i]==x){
  80. a[i]=y;
  81. sum1[bl[l]][bl[x]]--;
  82. sum1[bl[l]][bl[y]]++;
  83. sum2[bl[l]][x]--;
  84. sum2[bl[l]][y]++;
  85. }
  86. for(int i=L[bl[r]];i<=r;i++)
  87. if(a[i]==x){
  88. a[i]=y;
  89. sum1[bl[r]][bl[x]]--;
  90. sum1[bl[r]][bl[y]]++;
  91. sum2[bl[r]][x]--;
  92. sum2[bl[r]][y]++;
  93. }
  94. build(bl[l]);build(bl[r]);
  95. for(int i=bl[l]+1;i<bl[r];i++){
  96. if(!sum2[i][x]) continue;
  97. if(sum2[i][y]){
  98. reset(i);
  99. for(int j=L[i];j<=R[i];j++)
  100. if(a[j]==x){
  101. a[j]=y;
  102. sum1[i][bl[x]]--;
  103. sum1[i][bl[y]]++;
  104. sum2[i][x]--;
  105. sum2[i][y]++;
  106. }
  107. build(i);
  108. }
  109. else {
  110. sum1[i][bl[x]]-=sum2[i][x];
  111. sum1[i][bl[y]]+=sum2[i][x];
  112. sum2[i][y]+=sum2[i][x];
  113. sum2[i][x]=0;
  114. change(i,x,y);
  115. }
  116. }
  117. rebuild(l,x,y);
  118. }
  119. inline int query(int l,int r,int k){
  120. if(bl[l]==bl[r]){
  121. reset(bl[l]);
  122. for(int i=l;i<=r;i++) v1[i]=a[i];
  123. nth_element(v1+l,v1+l+k-1,v1+r+1);
  124. int ans=v1[l+k-1];
  125. for(int i=l;i<=r;i++) v1[i]=0;
  126. return ans;
  127. }
  128. reset(bl[l]);reset(bl[r]);
  129. for(int i=l;i<=R[bl[l]];i++) v1[bl[a[i]]]++,v2[a[i]]++;
  130. for(int i=L[bl[r]];i<=r;i++) v1[bl[a[i]]]++,v2[a[i]]++;
  131. for(int i=1;i<=bl[lim];i++){
  132. if(k>v1[i]+sum1[bl[r]-1][i]-sum1[bl[l]][i]) k-=v1[i]+sum1[bl[r]-1][i]-sum1[bl[l]][i];
  133. else {
  134. for(int j=(i-1)*blo+1;j<=i*blo;j++){
  135. if(k>v2[j]+sum2[bl[r]-1][j]-sum2[bl[l]][j]) k-=v2[j]+sum2[bl[r]-1][j]-sum2[bl[l]][j];
  136. else {
  137. for(int x=l;x<=R[bl[l]];x++) v1[bl[a[x]]]--,v2[a[x]]--;
  138. for(int x=L[bl[r]];x<=r;x++) v1[bl[a[x]]]--,v2[a[x]]--;
  139. return j;
  140. }
  141. }
  142. }
  143. }
  144. }
  145. int main()
  146. {
  147. read(n),read(m);blo=sqrt(lim)+1;
  148. for(int i=1;i<=n;i++) read(a[i]);
  149. for(int i=1;i<=lim;i++){
  150. bl[i]=(i-1)/blo+1;
  151. if(bl[i]!=bl[i-1]) L[bl[i]]=i,R[bl[i-1]]=i-1;
  152. }
  153. R[bl[n]]=n;
  154. for(int i=1;i<=bl[n];i++) build(i);
  155. for(int x=1;x<=bl[n];x++){
  156. for(int i=1;i<=bl[lim];i++) sum1[x][i]=sum1[x-1][i];
  157. for(int i=1;i<=lim;i++) sum2[x][i]=sum2[x-1][i];
  158. for(int i=L[x];i<=R[x];i++) sum1[x][bl[a[i]]]++,sum2[x][a[i]]++;
  159. }
  160. int op,l,r,x,y;
  161. while(m--){
  162. read(op),read(l),read(r),read(x);
  163. if(op==1) read(y),modify(l,r,x,y);
  164. else print(query(l,r,x));
  165. }
  166. return 0;
  167. }

[Ynoi2018]未来日记(分块)的更多相关文章

  1. [Ynoi2018]未来日记

    "望月悲叹的最初分块" (妈呀这名字好中二啊(谁叫我要用日本轻小说中的东西命名真是作死)) 这里就直接挂csy的题解了,和我的不太一样,但是大概思路还是差不多的,我的做法是和“五彩 ...

  2. 「Ynoi2018」未来日记

    「Ynoi2018」未来日记 区间x->y,kth值... 不管了,先序列分块... 查询 第k值,假定知道每个数的权值,对值域分块. 对于整块,维护前\(i\)个块当中,值域在\(j\)块里以 ...

  3. 洛谷P4117 [Ynoi2018]五彩斑斓的世界 [分块,并查集]

    洛谷 Codeforces 又是一道卡常题-- 思路 YNOI当然要分块啦. 分块之后怎么办? 零散块暴力,整块怎么办? 显然不能暴力改/查询所有的.考虑把相同值的用并查集连在一起,这样修改时就只需要 ...

  4. [YNOI2018]五彩斑斓的世界&CF896E(分块+并查集)

    由于晚上比赛二连(Atcoder&codeforces),外加复习学考,所以暂时没时间写了. 贴个O(n√n)的分块代码,洛谷和cf上都过了,但垃圾bzoj卡不过去,不改了. #include ...

  5. ynoi2018

    题解: 全分块是啥操作啊.. 而且都好难.. 1.未来日记 这个比较简单 对每个块开个线段树维护权值 $n\sqrt{n}logn$ 这个会炸空间 并不能做... 但还是说一下做法 首先考虑分块 然后 ...

  6. PHP搭建大文件切割分块上传功能

    背景 在网站开发中,文件上传是很常见的一个功能.相信很多人都会遇到这种情况,想传一个文件上去,然后网页提示"该文件过大".因为一般情况下,我们都需要对上传的文件大小做限制,防止出现 ...

  7. POJ2104 K-th Number [分块做法]

    传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求 ...

  8. HDU 4467 分块

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4467 题意:给定n个点m条边的无向图,点被染色(黑0/白1),边带边权.然后q个询问.询问分为两种: ...

  9. 2016 ACM/ICPC Asia Regional Dalian Online 1010 Weak Pair dfs序+分块

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submissio ...

随机推荐

  1. java中HashMap的基本方法使用

    遍历,添加词,等等 package test; import java.util.HashMap; import java.util.Iterator; import java.util.ArrayL ...

  2. Unity2017新功能Sprite Atlas详解

    Sprite Atlas(精灵图集)Sprite Atlas 针对现有的图集打包系统Sprite Packer在性能和易用性上的不足,进行了全面改善.除此之外,相比Sprite Packer,Spri ...

  3. Tkinter添加图片

    Tkinter添加图片的方式,与Java相似都是利用label标签来完成的: 一.默认的是gif的格式,注意将png后缀名修改为gif还是无法使用,文件格式依然错误. photo = PhotoIma ...

  4. trunc()用法和add_months()

    TRUNC函数用于对值进行截断. 用法有两种:TRUNC(NUMBER)表示截断数字,TRUNC(date)表示截断日期. (1)截断数字: 格式:TRUNC(n1,n2),n1表示被截断的数字,n2 ...

  5. PHP中两个冒号是什么意思

    类中 静态方法和静态属性的引用方法 对类的静态属性和方法的直接引用,这种情况可以不需要实例化类而直接使用“::”调用

  6. TCP/IP协议(7):应用层

    应用层上协议有DNS.DHCP.HTTP.SSL/TLS.FTP.Telnet等. 1.DNS域名解析 DNS服务器用来解析域名从而获得对应IP地址,我们在对网络进行设置的时候如果DNS服务器没有设置 ...

  7. myBatis中if test 字符串注意事项

    错误写法: <if test="userName == 'boshen'"> AND `USER_NAME` = #{userName} </if> 正确写 ...

  8. openstack路由管理命令

    1.命令一览 [root@cc07 ~]# neutron help | grep route bgp-speaker-advertiseroute-list List routes advertis ...

  9. FoonSunCMS-Word图片上传功能-Xproer.WordPaster

    1.1. 与FoosunCMS 3.1.0930整合 基于WordPaster-asp-CKEditor4.x示例 下载地址:http://www.ncmem.com/download/WordPas ...

  10. Gitolite 权限控制

    官网 http://gitolite.com/gitolite/index.html 安装配置 http://gitolite.com/gitolite/install/ 傻瓜安装教程 http:// ...