题目

有n个数编号从0→n-1,两种操作:

Q L R:询问编号为L→R-1的数中共有多少种不同的数

M X Y:将编号为X的数改为Y

共有m个操作

分析

既然是单点修改,查询,我们考虑一下分块。

首先,定义\(next_{i}\)表示,在\(i\)之后的第一个与编号为\(i\)的数相同的数的位置。

接着,我们把\(i\)向\(next_{i}\)连一条边。

那么就会发现,当把边处理好后,查询操作就迎刃而解了;

查询操作

假设现在要查询\([x,y]\),



其中next,以及它们的连边的情况是:



发现,编号为\(a\)的数和编号为\(next_a\)的数的数以及编号为\(b\)的数和编号为\(next_b\)的数的数都重复了。

那么就要减去重复的,

而编号为\(next_c\)的数并不在\([x,y]\),所以并不需要减去。

我们得出一个结论:\(\color{red}{当next_i<=y时,编号为i的数一定有重复,所以我们就只记录最后一个,即next_i>y的那一个}\)

那如何处理呢?

对于不是整块的部分,暴力处理。时间复杂度\(O(2\sqrt{n})\)。

对于整块的部分,把整块按\(next_{i}\)排序,二分求答案。

修改操作

我们再定义\(last_{i}\)表示,在\(i\)之前的第一个与编号为\(i\)的数相同的数的位置。

再把\(i\)向\(last_{i}\)连一条边;

假设我们修改位置x,



那么,因为x修改成别的值,所以\(next[last[x]]\)就要就修成\(next[x]\),\(last[next[x]]\)就要就改成\(last[x]\)

接着,发现,这样\(next[last[x]]\)改变了,于是,重新把\(last[x]\)所在的块排序。

然后,就要处理位置x新的\(last和next\)。

假设x所在的块的开头和结尾是s和t。



处理\(last\):

我们先暴力查看x-1~s的位置中是否出现过y,如果有,修改\(last[x]\)以及\(next[last[x]]\)。

否则查看前面的块,

再定义\(sum[i][j]\)表示,在第i个块中,j这个数出现过多少次。

找到了,就修改就可以了。

处理\(next\)类似。

记住,如果某个位置的\(next\)修改了,就将这个位置所在的块排个序。

  1. #include <cmath>
  2. #include <iostream>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <cstring>
  6. #include <algorithm>
  7. #include <queue>
  8. const int maxlongint=2147483647;
  9. const int mo=1000000007;
  10. const int N=50005;
  11. using namespace std;
  12. int a[N*2],n,m,ans,next[N*2],last[N*2],part[N][2],size,as[N*2],pos[N*2],stead[1000005],sum[250][N*2],tot,color[N*2],num;
  13. bool cmp(int x,int y)
  14. {
  15. return next[x]<next[y];
  16. }
  17. int preblock()
  18. {
  19. size=sqrt(n);
  20. for(int i=1;i<=n;i+=size)
  21. {
  22. part[++tot][0]=i;
  23. if(i+size-1>n)
  24. part[tot][1]=n;
  25. else
  26. part[tot][1]=i+size-1;
  27. }
  28. for(int i=1;i<=tot;i++)
  29. for(int j=part[i][0];j<=part[i][1];j++)
  30. {
  31. sum[i][stead[a[j]]]++;
  32. pos[j]=i;
  33. }
  34. }
  35. int prenexus()
  36. {
  37. memset(color,0,sizeof(color));
  38. for(int i=0;i<=n;i++)
  39. {
  40. last[i]=color[stead[a[i]]];
  41. color[stead[a[i]]]=i;
  42. }
  43. memset(color,0,sizeof(color));
  44. for(int i=n;i>=0;i--)
  45. {
  46. next[i]=color[stead[a[i]]];
  47. if(!next[i])
  48. next[i]=maxlongint;
  49. color[stead[a[i]]]=i;
  50. }
  51. }
  52. int so(int x)
  53. {
  54. sort(as+part[x][0],as+part[x][1]+1,cmp);
  55. }
  56. int fs(int x,int y,int y1)
  57. {
  58. for(int i=x;i<=y;i++)
  59. if(next[i]>y1)
  60. ans++;
  61. }
  62. int zt(int x,int y,int y1)
  63. {
  64. int ll=x-1,rr=y;
  65. while(ll<rr-1)
  66. {
  67. int mid=(ll+rr)/2;
  68. if(next[as[mid]]<=y1) ll=mid;
  69. else rr=mid;
  70. }
  71. int q=0;
  72. if(next[as[rr]]<=y1) q=rr;
  73. else q=ll;
  74. ans+=y-x+1-(q-x+1);
  75. }
  76. int main()
  77. {
  78. scanf("%d%d",&n,&m);
  79. for(int i=1;i<=n;i++)
  80. {
  81. scanf("%d",&a[i]);
  82. if(!stead[a[i]])
  83. {
  84. stead[a[i]]=++num;
  85. }
  86. }
  87. preblock();
  88. prenexus();
  89. for(int i=1;i<=n;i++) as[i]=i;
  90. for(int i=1;i<=tot;i++) so(i);
  91. for(int k=1;k<=m;k++)
  92. {
  93. char c=getchar();
  94. while(c!='Q' && c!='M') c=getchar();
  95. int x,y;
  96. scanf(" %d %d",&x,&y);
  97. x+=1;
  98. if(c=='Q')
  99. {
  100. ans=0;
  101. int l=pos[x],r=pos[y];
  102. if(l==r)
  103. {
  104. for(int i=x;i<=y;i++)
  105. if(next[i]>y) ans++;
  106. printf("%d\n",ans);
  107. continue;
  108. }
  109. if(x>part[l][0])
  110. {
  111. for(int i=x;i<=part[l][1];i++)
  112. if(next[i]>y) ans++;
  113. l++;
  114. }
  115. if(y<part[r][1])
  116. {
  117. for(int i=part[r][0];i<=y;i++)
  118. if(next[i]>y) ans++;
  119. r--;
  120. }
  121. for(int i=l;i<=r;i++)
  122. zt(part[i][0],part[i][1],y);
  123. printf("%d\n",ans);
  124. }
  125. else
  126. {
  127. bool q=true;
  128. if(!stead[y])
  129. {
  130. stead[y]=++num;
  131. q=false;
  132. }
  133. next[last[x]]=next[x];
  134. if(next[x]!=maxlongint)
  135. last[next[x]]=last[x];
  136. sum[pos[x]][stead[a[x]]]--;
  137. sum[pos[x]][stead[y]]++;
  138. so(pos[last[x]]);
  139. a[x]=y;
  140. if(!q)
  141. {
  142. last[x]=0;
  143. next[x]=maxlongint;
  144. }
  145. else
  146. {
  147. int p=0,p1=0;
  148. for(int i=x-1;i>=part[pos[x]][0];i--)
  149. if(a[i]==y)
  150. {
  151. p=i;
  152. break;
  153. }
  154. if(!p)
  155. {
  156. for(int i=pos[x]-1;i>=1;i--)
  157. {
  158. if(sum[i][stead[y]])
  159. {
  160. for(int j=part[i][1];j>=part[i][0];j--)
  161. if(a[j]==y)
  162. {
  163. p=j;
  164. break;
  165. }
  166. break;
  167. }
  168. }
  169. }
  170. if(p)
  171. {
  172. last[x]=p;
  173. next[p]=x;
  174. so(pos[p]);
  175. }
  176. else
  177. last[x]=0;
  178. for(int i=x+1;i<=part[pos[x]][1];i++)
  179. if(a[i]==y)
  180. {
  181. p1=i;
  182. break;
  183. }
  184. if(!p1)
  185. {
  186. for(int i=pos[x]+1;i<=tot;i++)
  187. {
  188. if(sum[i][stead[y]])
  189. {
  190. for(int j=part[i][0];j<=part[i][1];j++)
  191. if(a[j]==y)
  192. {
  193. p1=j;
  194. break;
  195. }
  196. break;
  197. }
  198. }
  199. }
  200. if(p1)
  201. {
  202. next[x]=p1;
  203. last[p1]=x;
  204. so(pos[x]);
  205. }
  206. else
  207. next[x]=maxlongint;
  208. }
  209. so(pos[x]);
  210. }
  211. }
  212. }

Dynamic len的更多相关文章

  1. Uva 3767 Dynamic len(set(a[L:R])) 树套树

    Dynamic len(set(a[L:R])) Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://uva.onlinejudge.org/in ...

  2. UVA 12345 Dynamic len(带修莫队)

    Dynamic len [题目链接]Dynamic len [题目类型]带修莫队 &题解: 莫队可以单点更改,只要再多加一维,代表查询次数,排序的时候3个关键字. 之后循环离线的时候,先暴力时 ...

  3. 【题解】Luogu UVA12345 Dynamic len(set(a[L:R]))

    原题传送门 这题要用动态莫队,我博客里有介绍 这道题和luogu P1903 [国家集训队]数颜色 / 维护队列差不多,解法就在上面那篇博客里qaq 主要的问题是如何排序? 排序有三个关键字: 1.左 ...

  4. (待修莫队 没过! 抽空在检查)Dynamic len(set(a[L:R])) UVA - 12345

    #include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...

  5. Dynamic len(set(a[L:R])) UVA - 12345(这么过分一定要写博客)

    给出一个有n个元素的数组,有以下两种操作:Q x y,求出区间[x,y)内不同元素的个数, M x y,把第x个元素的值修改为y.注意题目中的下标是从0开始的 这题超级超级坑 妈的一个水题找了几个小时 ...

  6. UVA 12345 Dynamic len(set(a[LR]))

    题意:询问区间唯一元素个数,单点修改. 分析: 借助Unique snowflakes, Can you answer these queries II的思想,唯一性可以借助元素上一次出现的位置来判断 ...

  7. [UVa12345] Dynamic len (带 修 )

    题意:有n个数编号从0→n-1,两种操作:            Q L R:询问编号为L→R-1的数中共有多少种不同的数             M X Y:将编号为X的数改为Y           ...

  8. UESTC-1259 昊昊爱运动 II

    昊昊爱运动 II Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)     昊昊喜 ...

  9. UVA12345 (带修改的莫队)

    UVA12345 Dynamic len Problem : 给一个序列,每次询问一个区间里面的数字种类数量,或者修改某一个位置的值. Solution : 第一关键字分块排序左端点,第二关键字分块排 ...

随机推荐

  1. 自定义配置节点configSections的使用

    //App.config <?xml version="1.0" encoding="utf-8" ?><configuration>  ...

  2. svn访问版本库时一直提示: please wait while the repository browser is initializing

    最近不知道做了什么操作,原来正常的SVN Check In/Out都无法正常操作. 正常Check In的动作,几秒钟就会操作完成,但是我却等了好久好久,然后提示Connection timed ou ...

  3. 4.1.k8s.svc(Service)

    #Service Service为Pod提供4层负载均衡, 访问 -> Service -> Pod组 #4种类型 ClusterIP 默认,分配一个VIP,只能内部访问 NodePort ...

  4. Nil Channels Always Block(Go语言中空管道总是阻塞)

    译自:https://www.godesignpatterns.com/2014/05/nil-channels-always-block.html 原作者:Alex Lockwood 在本篇文章中, ...

  5. idea中怎么去查看maven项目的依赖包是否有冲突

    1:快捷键:

  6. 应用安全 - 工具 - NScan - 漏洞汇总

    工具介绍 Date 用途 端口服务扫描 | whois | nslookup Nscan v0.9.1 缓冲区溢出导致远程代码执行 Date 类型缓冲区溢出导致远程代码执行 影响范围 复现字符量过多 ...

  7. 国家授时中心的NTP服务器地址 210.72.145.44

    国家授时中心的NTP服务器地址 210.72.145.44

  8. mysql常用知识点之limit

    limit函数的应用.limit后面跟整数,如limit 5,表示在结果集中取前5条:limit后跟整数区间,如limit 2,5,表示在结果集中 从第3条开始,取5条数据,第一个整数表示结果集的顺序 ...

  9. Bean与Map的转换 和 Map与Bean的转换

    package com.JUtils.beanConvert; import java.beans.BeanInfo; import java.beans.IntrospectionException ...

  10. vue插槽用法(极客时间Vue视频笔记)

    vue插槽 插槽是用来传递复杂的内容,类似方法 <!DOCTYPE html> <html lang="en"> <head> <meta ...