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
 
 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N (1000000+100)
using namespace std;
int Size[N],Key[N];//key[i]中存的是编号为i的颜色,用序列的编号大小来建splay,节点里存颜色
int Father[N],Son[N][];
int n,m,Root[N],ans,a[N];
int flag; int Get(int x){return Son[Father[x]][]==x;}
void Update(int x){Size[x]=Size[Son[x][]]+Size[Son[x][]]+;}
void Clear(int x){Key[x]=Father[x]=Son[x][]=Son[x][]=Size[x]=;} void Rotate(int x)
{
int wh=Get(x);
int fa=Father[x],fafa=Father[fa];
Son[fa][wh]=Son[x][wh^];
Father[fa]=x;
if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
Son[x][wh^]=fa;
Father[x]=fafa;
if (fafa) Son[fafa][Son[fafa][]==fa]=x;
Update(fa);
Update(x);
} void Splay(int x,int &root)
{
for (int fa;fa=Father[x];Rotate(x))
if (Father[fa])
Rotate(Get(fa)==Get(x)?fa:x);
root=x;
} void Insert(int x,int color,int &root)
{
if (root==)
{
Size[x]=;
Key[x]=color;
root=x;
return;
}
int now=root,fa=;
while ()
{
fa=now;now=Son[now][x>now];
if (now==)
{
Size[x]=;
Key[x]=color;
Father[x]=fa;
Son[fa][x>fa]=x;
Update(fa);
Splay(x,root);
return;
}
}
} void Change(int x,int &root,int color)//唯一需要注意的函数,参数:(被拆的splay的当前节点,合并到的splay的根,需要改成什么颜色)。按中序遍历将要拆的splay一个个拆掉就好
{
if (Son[x][]) Change(Son[x][],root,color); int rson=Son[x][];//因为下面要clear x这个节点的信息,所以事先存一下
int pre_color=Key[x];//同上
if (!flag && Key[x]!=Key[x-]) flag=+(color==Key[x-]);//☆如果x是连续序列的开始,就把flag改成1。如果不仅是开始,还能和前一个连起来,flag再加一。(flag在连续序列结束的地方会用到)
Clear(x);
Insert(x,color,root);//插入到目标splay中
if (Key[x]==Key[x+]) ans-=;//如果当前是连续序列的结束且这个点能和后面的颜色接上,ans--。
if (Key[x+]!=pre_color) ans-=flag-,flag=;//如果这个点是结束,ans根据开头是否接上判断减不减。flag归零。 if (rson) Change(rson,root,color);
} int main()
{
scanf("%d%d",&n,&m);
for (int i=;i<=n;++i)
{
scanf("%d",&a[i]);
if (a[i]!=a[i-]) ans++;
Insert(i,a[i],Root[a[i]]);
}
int opt,x,y;
for (int i=;i<=m;++i)
{
scanf("%d",&opt);
if (opt==)
{
scanf("%d%d",&x,&y);
if (Root[x]== || x==y) continue;//如果当前颜色没有节点 或者 这次更改前后的颜色是一样的 就不用做了(因为做了会卡)
Change(Root[x],Root[y],y);
Root[x]=;
}
if (opt==) printf("%d\n",ans);
}
}

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. SQL——Sql_Server中如何判断表中某字段、判断表、判断存储过程以及判断函数是否存在

    一.比如说要判断表A中的字段C是否存在两个方法: (1) 直接查表——有点笨,有点常规 IF EXISTS ( SELECT 1 FROM SYSOBJECTS T1 INNER JOIN SYSCO ...

  2. 前端模块化(AMD和CMD、CommonJs)

    知识点1:AMD/CMD/CommonJs是JS模块化开发的标准,目前对应的实现是RequireJs/SeaJs/nodeJs. 知识点2:CommonJs主要针对服务端,AMD/CMD主要针对浏览器 ...

  3. 前端(九):react生命周期

    一.组件渲染 当组件的props或者state发生改变时,组件会自动调用render方法重新渲染.当父组件被重新渲染时,子组件也会被递归渲染.那么组件是如何渲染的呢? # 方案一 1.state数据 ...

  4. Android开发之旅5:应用程序基础及组件

    引言 上篇Android开发之旅:应用程序基础及组件介绍了应用程序的基础知识及Android的四个组件,本篇将介绍如何激活组关闭组件等.本文的主题如下: 1.激活组件:意图(Intents) 1.1. ...

  5. border-radius 移动之伤

    border-radius我相信对于老一辈的前端们有着特殊的感情,在经历了没有圆角的蛮荒时代,到如今 CSS3 遍地开花,我们还是很幸福的. 然而即使到了三星大脸流行时代,border-radius在 ...

  6. setTimeout OR setInterval?

    setTimeout 和setInterval从字面上应该是可以知道其大意的.timeout:延时:interval:间隔: 两者的区别就像是它们自己的英文解释一样:setTimeout是延时执行,并 ...

  7. TCP报文发送工具

    该工具用于向Socket服务端发送XML报文,软件功能界面如下图所示: 配置好IP和端口后,单击"载入报文文件"按钮,在文件选择对话框中选择报文文件,如图: 报文文件打开后,可在右 ...

  8. elixir mac环境

    1.升级brew brew update 2.安装 erlang brew install erlang 3.安装Elixir: brew install elixir 终端 iex iex> ...

  9. c# 异步和同步问题(转载)

    [C#] 谈谈异步编程async await   为什么需要异步,异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要. 对 Web 资源的访问有时很慢或会延迟. 如果此类活动在同步过 ...

  10. Object hashcode

    java jvm怎么找到一个对象? 一个对象有一个独一无二的hashcode,这样就可以找到这个对象了. 但java 的hashcode 实现的不好,有可能两个不同的对象有一个相同的hashcode, ...