题目描述

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

输入

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

样例输入

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

样例输出

4
4
3
4

提示

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

 
带修改莫队模板题

  1. #include<set>
  2. #include<map>
  3. #include<queue>
  4. #include<stack>
  5. #include<cmath>
  6. #include<cstdio>
  7. #include<bitset>
  8. #include<vector>
  9. #include<cstring>
  10. #include<iostream>
  11. #include<algorithm>
  12. #define ll long long
  13. using namespace std;
  14. struct lty
  15. {
  16. int l,r,num,tim;
  17. }q[10010];
  18. struct miku
  19. {
  20. int x,y;
  21. }a[10010];
  22. int res;
  23. int v[1000010];
  24. int s[100010];
  25. int ans[100010];
  26. int num,cnt;
  27. int n,m;
  28. int block;
  29. char ch[20];
  30. bool cmp(lty a,lty b)
  31. {
  32. return (a.l/block==b.l/block)?(a.r==b.r?a.tim<b.tim:a.r<b.r):a.l<b.l;
  33. }
  34. void del(int x)
  35. {
  36. if(v[x]==1)
  37. {
  38. res--;
  39. }
  40. v[x]--;
  41. }
  42. void ins(int x)
  43. {
  44. if(!v[x])
  45. {
  46. res++;
  47. }
  48. v[x]++;
  49. }
  50. void change(int l,int r,int id)
  51. {
  52. if(a[id].x>=l&&a[id].x<=r)
  53. {
  54. if(--v[s[a[id].x]]==0)
  55. {
  56. res--;
  57. }
  58. if(++v[a[id].y]==1)
  59. {
  60. res++;
  61. }
  62. }
  63. swap(a[id].y,s[a[id].x]);
  64. }
  65. int main()
  66. {
  67. scanf("%d%d",&n,&m);
  68. block=pow(n,2/3);
  69. for(int i=1;i<=n;i++)
  70. {
  71. scanf("%d",&s[i]);
  72. }
  73. for(int i=1;i<=m;i++)
  74. {
  75. scanf("%s",ch);
  76. if(ch[0]=='Q')
  77. {
  78. cnt++;
  79. scanf("%d%d",&q[cnt].l,&q[cnt].r);
  80. q[cnt].num=cnt,q[cnt].tim=num;
  81. }
  82. else
  83. {
  84. num++;
  85. scanf("%d%d",&a[num].x,&a[num].y);
  86. }
  87. }
  88. sort(q+1,q+1+cnt,cmp);
  89. int L=1,R=0,now=0;
  90. for(int i=1;i<=cnt;i++)
  91. {
  92. while(L>q[i].l)
  93. {
  94. L--;
  95. ins(s[L]);
  96. }
  97. while(R<q[i].r)
  98. {
  99. R++;
  100. ins(s[R]);
  101. }
  102. while(L<q[i].l)
  103. {
  104. del(s[L]);
  105. L++;
  106. }
  107. while(R>q[i].r)
  108. {
  109. del(s[R]);
  110. R--;
  111. }
  112. while(now<q[i].tim)
  113. {
  114. now++;
  115. change(q[i].l,q[i].r,now);
  116. }
  117. while(now>q[i].tim)
  118. {
  119. change(q[i].l,q[i].r,now);
  120. now--;
  121. }
  122. ans[q[i].num]=res;
  123. }
  124. for(int i=1;i<=cnt;i++)
  125. {
  126. printf("%d\n",ans[i]);
  127. }
  128. }
对于每个点,记录这个点的颜色上一次出现的位置作为这个点的点权,每次查询l,r就相当于查询l到r之间点权小于l的点有多少个。实现起来直接用树套树就好了,外层用线段树维护序列区间信息,内层平衡树维护区间排名,每次只要找线段树对应点的平衡树内l的排名就好了。但修改比较麻烦,每次修改x点需要改变x修改前颜色中x的后继的前驱、x的前驱和修改后颜色中x的后继的前驱。对于每种颜色开一个set来维护前驱后继,每次修改时对应修改就好了,但要注意判断x是否有前驱和后继。
  1. #include<set>
  2. #include<map>
  3. #include<queue>
  4. #include<stack>
  5. #include<cmath>
  6. #include<cstdio>
  7. #include<vector>
  8. #include<cstring>
  9. #include<iostream>
  10. #include<algorithm>
  11. #define ll long long
  12. using namespace std;
  13. int x,y;
  14. int n,m;
  15. int tot;
  16. int opt;
  17. char ch[3];
  18. int a[50010];
  19. int v[2000010];
  20. int w[2000010];
  21. int t[2000010];
  22. int l[500010];
  23. int r[500010];
  24. int ls[2000010];
  25. int rs[2000010];
  26. int pre[50010];
  27. int suf[50010];
  28. int size[2000010];
  29. int root[500010];
  30. map<int,int>b;
  31. set<int>s[1000010];
  32. set<int>::iterator it;
  33. int inbuild(int k)
  34. {
  35. tot++;
  36. t[tot]=rand();
  37. v[tot]=k;
  38. w[tot]=1;
  39. size[tot]=1;
  40. ls[tot]=rs[tot]=0;
  41. return tot;
  42. }
  43. void updata(int rt)
  44. {
  45. size[rt]=size[ls[rt]]+size[rs[rt]]+w[rt];
  46. }
  47. void lturn(int &rt)
  48. {
  49. int t=rs[rt];
  50. rs[rt]=ls[t];
  51. ls[t]=rt;
  52. updata(rt);
  53. updata(t);
  54. rt=t;
  55. }
  56. void rturn(int &rt)
  57. {
  58. int t=ls[rt];
  59. ls[rt]=rs[t];
  60. rs[t]=rt;
  61. updata(rt);
  62. updata(t);
  63. rt=t;
  64. }
  65. void insert(int &rt,int k)
  66. {
  67. if(!rt)
  68. {
  69. rt=inbuild(k);
  70. return ;
  71. }
  72. if(v[rt]==k)
  73. {
  74. w[rt]++;
  75. }
  76. else
  77. {
  78. if(k<v[rt])
  79. {
  80. insert(ls[rt],k);
  81. if(t[ls[rt]]<t[rt])
  82. {
  83. rturn(rt);
  84. }
  85. }
  86. else
  87. {
  88. insert(rs[rt],k);
  89. if(t[rs[rt]]<t[rt])
  90. {
  91. lturn(rt);
  92. }
  93. }
  94. }
  95. updata(rt);
  96. }
  97. void del(int &rt,int k)
  98. {
  99. if(v[rt]<k)
  100. {
  101. del(rs[rt],k);
  102. }
  103. else if(v[rt]>k)
  104. {
  105. del(ls[rt],k);
  106. }
  107. else
  108. {
  109. if(w[rt]>1)
  110. {
  111. w[rt]--;
  112. }
  113. else
  114. {
  115. if(!ls[rt]||!rs[rt])
  116. {
  117. rt=ls[rt]+rs[rt];
  118. }
  119. else
  120. {
  121. if(t[ls[rt]]<t[rs[rt]])
  122. {
  123. rturn(rt);
  124. del(rs[rt],k);
  125. }
  126. else
  127. {
  128. lturn(rt);
  129. del(ls[rt],k);
  130. }
  131. }
  132. }
  133. }
  134. if(rt)
  135. {
  136. updata(rt);
  137. }
  138. }
  139. int inrank(int rt,int k)
  140. {
  141. if(!rt)
  142. {
  143. return 0;
  144. }
  145. if(v[rt]==k)
  146. {
  147. return size[ls[rt]];
  148. }
  149. else if(v[rt]<k)
  150. {
  151. return size[ls[rt]]+w[rt]+inrank(rs[rt],k);
  152. }
  153. else
  154. {
  155. return inrank(ls[rt],k);
  156. }
  157. }
  158. void outbuild(int rt,int L,int R)
  159. {
  160. l[rt]=L;
  161. r[rt]=R;
  162. for(int i=L;i<=R;i++)
  163. {
  164. insert(root[rt],pre[i]);
  165. }
  166. if(L!=R)
  167. {
  168. int mid=(L+R)>>1;
  169. outbuild(rt<<1,L,mid);
  170. outbuild(rt<<1|1,mid+1,R);
  171. }
  172. }
  173. void change(int rt,int x,int y)
  174. {
  175. del(root[rt],pre[x]);
  176. insert(root[rt],y);
  177. if(l[rt]!=r[rt])
  178. {
  179. int mid=(l[rt]+r[rt])>>1;
  180. if(x<=mid)
  181. {
  182. change(rt<<1,x,y);
  183. }
  184. else
  185. {
  186. change(rt<<1|1,x,y);
  187. }
  188. }
  189. }
  190. int outrank(int rt,int L,int R,int k)
  191. {
  192. if(L<=l[rt]&&r[rt]<=R)
  193. {
  194. return inrank(root[rt],k);
  195. }
  196. int mid=(l[rt]+r[rt])>>1;
  197. if(R<=mid)
  198. {
  199. return outrank(rt<<1,L,R,k);
  200. }
  201. else if(L>mid)
  202. {
  203. return outrank(rt<<1|1,L,R,k);
  204. }
  205. return outrank(rt<<1,L,R,k)+outrank(rt<<1|1,L,R,k);
  206. }
  207. int main()
  208. {
  209. srand(12378);
  210. scanf("%d%d",&n,&m);
  211. for(int i=1;i<=n;i++)
  212. {
  213. scanf("%d",&a[i]);
  214. pre[i]=b[a[i]];
  215. suf[b[a[i]]]=i;
  216. b[a[i]]=i;
  217. s[a[i]].insert(i);
  218. }
  219. for(int i=1;i<=n;i++)
  220. {
  221. if(!suf[i])
  222. {
  223. suf[i]=n+1;
  224. }
  225. }
  226. outbuild(1,1,n);
  227. for(int i=1;i<=m;i++)
  228. {
  229. scanf("%s",ch);
  230. if(ch[0]=='R')
  231. {
  232. scanf("%d%d",&x,&y);
  233. if(a[x]==y)
  234. {
  235. continue;
  236. }
  237. if(pre[x])
  238. {
  239. suf[pre[x]]=suf[x];
  240. }
  241. if(suf[x]!=n+1)
  242. {
  243. change(1,suf[x],pre[x]);
  244. pre[suf[x]]=pre[x];
  245. }
  246. s[a[x]].erase(x);
  247. a[x]=y;
  248. s[a[x]].insert(x);
  249. it=s[a[x]].lower_bound(x);
  250. if(it!=s[a[x]].begin())
  251. {
  252. it--;
  253. suf[(*it)]=x;
  254. change(1,x,(*it));
  255. pre[x]=(*it);
  256. it++;
  257. }
  258. else
  259. {
  260. change(1,x,0);
  261. pre[x]=0;
  262. }
  263. if(++it!=s[a[x]].end())
  264. {
  265. suf[x]=(*it);
  266. change(1,(*it),x);
  267. pre[(*it)]=x;
  268. }
  269. else
  270. {
  271. suf[x]=n+1;
  272. }
  273. }
  274. else
  275. {
  276. scanf("%d%d",&x,&y);
  277. printf("%d\n",outrank(1,x,y,x));
  278. }
  279. }
  280. }

BZOJ2120&2453数颜色——线段树套平衡树(treap)+set/带修改莫队的更多相关文章

  1. 树套树Day1线段树套平衡树bzoj3196

    您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查 ...

  2. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2271  Solved: 935[Submit][Stat ...

  3. BZOJ3196二逼平衡树——线段树套平衡树(treap)

    此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询 ...

  4. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  5. bzoj 2120 线段树套平衡树

    先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心..... 首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有, 但是能给我们一 ...

  6. P3380 【模板】二逼平衡树(树套树) 线段树套平衡树

    \(\color{#0066ff}{ 题目描述 }\) 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上 ...

  7. BZOJ3196 二逼平衡树 【线段树套平衡树】

    题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...

  8. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  9. CF 19D - Points 线段树套平衡树

    题目在这: 给出三种操作: 1.增加点(x,y) 2.删除点(x,y) 3.询问在点(x,y)右上方的点,如果有相同,输出最左边的,如果还有相同,输出最低的那个点 分析: 线段树套平衡树. 我们先离散 ...

随机推荐

  1. MySQL(六)常用语法和数据类型

    阅读MySQL语法时,需要注意的规则: ①符号用来指出几个选择中的一个,比如:null | not null表示或者给出null或者给出not null: ②包含在方括号中的关键字或子句(如[like ...

  2. linux中断源码分析 - 软中断(四)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 在上一篇文章中,我们看到中断实际分为了两个部分,俗称就是一部分是硬中断,一部分是软中断.软中断是专门用于处理中断 ...

  3. eclpse安装jetty插件

    公司不用tomcat,使用的是jetty,那么学习一下如何在eclipse中安装jetty插件.

  4. php实现一个单链表

    单链表,节点只有一个指针域的链表.节点包括数据域和指针域. 因此用面向对象的思维,节点类的属性就有两个:一个data(表示存储的数据),一个指针next(链表中指向下一个节点). 链表一个很重要的特性 ...

  5. NOI.ac #31 MST DP、哈希

    题目传送门:http://noi.ac/problem/31 一道思路好题考虑模拟$Kruskal$的加边方式,然后能够发现非最小生成树边只能在一个已经由边权更小的边连成的连通块中,而树边一定会让两个 ...

  6. 搭建SpringBoot+dubbo+zookeeper+maven框架(二)

    上一篇文章是关于搭建SpringBoot+dubbo+zookeeper+maven框架的,但是里面的功能还不够完善,今天就日志管理方面做一些改善. 下了demo的网友可能会发现项目在启动时会有警告: ...

  7. VS2015 搭建 Asp.net core 开发环境

    1.首先你得装个vs2015 并且保证已经升级至 update3及以上(此处附上一个vs2015带up3的下载链接: ed2k://|file|cn_visual_studio_enterprise_ ...

  8. linux监控文件夹内的文件数量

    开发的时候遇到一个问题,服务器一旦重启,项目生成的文件就丢失了,感觉很莫名其妙..一开始猜测是文件流没有关闭,检查了代码,感觉没毛病.于是先看看是关机丢失了文件还是开机被删除了.下面的脚本每秒执行一次 ...

  9. VS2010、VS2012、VS2013、VS2015、VS2017各版本产品激活秘钥

    Visual Studio 2017(VS2017) 企业版 Enterprise 注册码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QF Visual Studio 2017(VS201 ...

  10. 保留最新N份备份目录脚本

    如下所示,在/opt/backup下是备份目录,只需要保留最新的三份备份,在此之前的备份目录都要删除. [root@syslog-ng ~]# cd /opt/backup/ [root@syslog ...