Description

N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.
例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.

Input

第一行给出N,M表示布丁的个数和好友的操作次数. 
第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,
对于每个操作,
若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 
若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0。
n,m<=1000000

Output

针对第二类操作即询问,依次输出当前有多少段颜色.

Sample Input

4 3
1 2 2 1
2
1 2 1
2

Sample Output

3
1
 
调了一下午终于A掉了qwq……
学会启发式合并后,其实这个题就是裸题了
splay启发式合并,听起来很智能,只不过就是暴力将小splay上的点一个个insert到大splay上
这个题只需要将需要改的颜色的splay合并到目标颜色splay上就好了
(这个程序并没有从小的合并到大的,不过仍然很快,可能是数据太弱了)
只不过程序中有一些小细节需要注意就是了
细节详见code
 
  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #define N (1000000+100)
  6. using namespace std;
  7. int Size[N],Key[N];//key[i]中存的是编号为i的颜色,用序列的编号大小来建splay,节点里存颜色
  8. int Father[N],Son[N][];
  9. int n,m,Root[N],ans,a[N];
  10. int flag;
  11.  
  12. int Get(int x){return Son[Father[x]][]==x;}
  13. void Update(int x){Size[x]=Size[Son[x][]]+Size[Son[x][]]+;}
  14. void Clear(int x){Key[x]=Father[x]=Son[x][]=Son[x][]=Size[x]=;}
  15.  
  16. void Rotate(int x)
  17. {
  18. int wh=Get(x);
  19. int fa=Father[x],fafa=Father[fa];
  20. Son[fa][wh]=Son[x][wh^];
  21. Father[fa]=x;
  22. if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
  23. Son[x][wh^]=fa;
  24. Father[x]=fafa;
  25. if (fafa) Son[fafa][Son[fafa][]==fa]=x;
  26. Update(fa);
  27. Update(x);
  28. }
  29.  
  30. void Splay(int x,int &root)
  31. {
  32. for (int fa;fa=Father[x];Rotate(x))
  33. if (Father[fa])
  34. Rotate(Get(fa)==Get(x)?fa:x);
  35. root=x;
  36. }
  37.  
  38. void Insert(int x,int color,int &root)
  39. {
  40. if (root==)
  41. {
  42. Size[x]=;
  43. Key[x]=color;
  44. root=x;
  45. return;
  46. }
  47. int now=root,fa=;
  48. while ()
  49. {
  50. fa=now;now=Son[now][x>now];
  51. if (now==)
  52. {
  53. Size[x]=;
  54. Key[x]=color;
  55. Father[x]=fa;
  56. Son[fa][x>fa]=x;
  57. Update(fa);
  58. Splay(x,root);
  59. return;
  60. }
  61. }
  62. }
  63.  
  64. void Change(int x,int &root,int color)//唯一需要注意的函数,参数:(被拆的splay的当前节点,合并到的splay的根,需要改成什么颜色)。按中序遍历将要拆的splay一个个拆掉就好
  65. {
  66. if (Son[x][]) Change(Son[x][],root,color);
  67.  
  68. int rson=Son[x][];//因为下面要clear x这个节点的信息,所以事先存一下
  69. int pre_color=Key[x];//同上
  70. if (!flag && Key[x]!=Key[x-]) flag=+(color==Key[x-]);//☆如果x是连续序列的开始,就把flag改成1。如果不仅是开始,还能和前一个连起来,flag再加一。(flag在连续序列结束的地方会用到)
  71. Clear(x);
  72. Insert(x,color,root);//插入到目标splay中
  73. if (Key[x]==Key[x+]) ans-=;//如果当前是连续序列的结束且这个点能和后面的颜色接上,ans--。
  74. if (Key[x+]!=pre_color) ans-=flag-,flag=;//如果这个点是结束,ans根据开头是否接上判断减不减。flag归零。
  75.  
  76. if (rson) Change(rson,root,color);
  77. }
  78.  
  79. int main()
  80. {
  81. scanf("%d%d",&n,&m);
  82. for (int i=;i<=n;++i)
  83. {
  84. scanf("%d",&a[i]);
  85. if (a[i]!=a[i-]) ans++;
  86. Insert(i,a[i],Root[a[i]]);
  87. }
  88. int opt,x,y;
  89. for (int i=;i<=m;++i)
  90. {
  91. scanf("%d",&opt);
  92. if (opt==)
  93. {
  94. scanf("%d%d",&x,&y);
  95. if (Root[x]== || x==y) continue;//如果当前颜色没有节点 或者 这次更改前后的颜色是一样的 就不用做了(因为做了会卡)
  96. Change(Root[x],Root[y],y);
  97. Root[x]=;
  98. }
  99. if (opt==) printf("%d\n",ans);
  100. }
  101. }

1483. [HNOI2009]梦幻布丁【平衡树-splay】的更多相关文章

  1. bzoj 1483 [HNOI2009]梦幻布丁(链表+启发式合并)

    1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1818  Solved: 761[Submit][Status ...

  2. BZOJ 1483: [HNOI2009]梦幻布丁( 链表 + 启发式合并 )

    把相同颜色的串成一个链表, 然后每次A操作就启发式合并, 然后计算对答案的影响. ----------------------------------------------------------- ...

  3. BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]

    1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...

  4. bzoj 1483: [HNOI2009]梦幻布丁 启发式合并vector

    1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description N个 ...

  5. 1483: [HNOI2009]梦幻布丁

    1483: [HNOI2009]梦幻布丁 链接 分析: 启发式合并+链表. 代码: #include<cstdio> #include<algorithm> #include& ...

  6. bzoj 1483: [HNOI2009]梦幻布丁

    1483: [HNOI2009]梦幻布丁 Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1 ...

  7. [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

    [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并) 题面 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1 ...

  8. bzoj 1483: [HNOI2009]梦幻布丁 (链表启发式合并)

    Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色. 例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input ...

  9. BZOJ 1483 HNOI2009 梦幻布丁 名单+启示录式的合并

    标题效果:特定n布丁.每个人都有一个颜色布丁,所有的布丁反复有一定的颜色变化的颜色,颜色反复询问的段数 数据范围:n<=10W 色彩数<=100W 启发式合并名单0.0 从来不写清楚 实际 ...

随机推荐

  1. SpringBoot数据库访问(一)--------关系型数据库访问(RDBMS)

    关系型数据库访问(RDBMS) 采用JdbcTemplate.MyBatis.JPA.Hibernate等技术. 一.JdbcTemplate工具 在pom.xml添加boot-starter-jdb ...

  2. Java并发常见问题

    ConcurrentHashMap源码分析,参考:http://blog.csdn.net/do_smile/article/details/46911727 HashMap源码分析,参考:http: ...

  3. Java注解(二)

    前面了解了注解的基本内容,这次来看一下自定义注解. 自定义注解其实很简单,直接上代码: import java.lang.annotation.Documented; import java.lang ...

  4. Linux 添加定时任务,crontab -e 命令与直接编辑 /etc/crontab 文件

    1. 使用 crontab -e 命令编辑定时任务列表 使用这个命令编辑的定时任务列表是属于用户级别的,初次编辑后在 /var/spool/cron 目录下生成一个与用户名相同的文件,文件内容就是我们 ...

  5. Java - HashMap值大于128问题

    class Solution { public boolean wordPattern(String pattern, String str) { HashMap<Character,Integ ...

  6. local_listener参数的作用!

    转自:http://warehouse.itpub.net/post/777/472788 pmon只会动态注册port等于1521的监听,否则pmon不能动态注册listener,要想让pmon动态 ...

  7. java ee思维导图

    该图是以网上的脑图作为参考,结合教材具体内容完成.

  8. maven Could not find artifact com.** 无法下载原因分析

    1.有时候经常莫名其妙的遇到这个问题:比如在idea重新导入一个新项目,或者在原来的空间里面引入一个新项目.去私服里面查看明明是有的,但是就是下载不下来. 结合网上搜的和自己遇到的,总结原因如下: 1 ...

  9. machine learning model(algorithm model) .vs. statistical model

    https://www.analyticsvidhya.com/blog/2015/07/difference-machine-learning-statistical-modeling/ http: ...

  10. python函数修饰器(decorator)

    python语言本身具有丰富的功能和表达语法,其中修饰器是一个非常有用的功能.在设计模式中,decorator能够在无需直接使用子类的方式来动态地修正一个函数,类或者类的方法的功能.当你希望在不修改函 ...