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

Output

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

Sample Input

4 3
1 2 2 1
2
1 2 1
2

Sample Output

3
1

HINT

Source

【分析】

转来的启发式合并的复杂度均摊分析:orzz

每次我们把短的合并到长的上面去,O(短的长度) 
咋看之下没有多大区别,
下面让我们看看均摊的情况:
1:每次O(N)
2:每次合并后,队列长度一定大于等于原来短的长度的两倍。
这样相当于每次合并都会让短的长度扩大一倍以上,
最多扩大logN次,所以总复杂度O(NlogN),每次O(logN)。
 
就是裸题了,搞一个链表把每种颜色段的开头位置记录下来,然后每次修改暴力修改+启发式合并就行。
还有就是记得把因为大小而导致错误的颜色用一个数组映射。
 /*
纳兰性德
人生若只如初见,何事秋风悲画扇。
等闲变却故人心,却道故人心易变。
骊山语罢清宵半,泪雨霖铃终不怨。
何如薄幸锦衣郎,比翼连枝当日愿。
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#include <stack>
#define LOCAL
const int MAXN = + ;
const int INF = ;
const int SIZE = ;
const int MAXM = + ;
const int maxnode = 0x7fffffff + ;
using namespace std;
struct Node{
int num;
Node *next;
}*head[MAXM];//head为表头
int cnt[MAXM], rem[MAXM], data[MAXM];
int tot, n, m; //在链表中加入颜色为x的节点
void add(int x, int d){//d代表位置
if (cnt[x] == ){
head[x] = new Node;
head[x]->num = d;
head[x]->next = NULL;
}else{
//在表头插入
Node *p = new Node;
p->num = d;
p->next = head[x];
head[x] = p;
}
}
void init(){
tot = ;//记录颜色的总数
memset(cnt, , sizeof(cnt));//记录颜色的数量
scanf("%d%d", &n, &m);
//for (int i = 1; i <= n; i++) rem[i] = i;
data[] = -INF;
for (int i = ; i <= n; i++){
scanf("%d", &data[i]);//输入颜色
if (data[i] != data[i - ]) tot++;
cnt[data[i]]++;
add(data[i], i);
rem[data[i]] = data[i];//防错数组初始化
} }
//将a颜色变成b颜色
void change(int a, int b){
//不要搞错了是比较正确颜色的个数
if (cnt[rem[a]] > cnt[rem[b]]) swap(rem[a], rem[b]);
a = rem[a];//总是让颜色数量少的变成多的
b = rem[b];
if (cnt[a] == ) return;
cnt[b] += cnt[a];
cnt[a] = ;
Node *cur;
for (cur = head[a]; cur != NULL; cur = cur->next){
if (data[cur->num + ] == b) tot--;
if (data[cur->num - ] == b) tot--;
}
for (cur = head[a]; cur->next != NULL; cur = cur->next) data[cur->num] = b;
data[cur->num] = b;
//最后将a插在b后面
cur->next = head[b];
head[b] = head[a];
}
void work(){
for (int i = ; i <= m; i++){
int t, a, b;
scanf("%d", &t);
if (t == ) printf("%d\n", tot);
else{
scanf("%d%d", &a, &b);
if (a == b) continue;//两种颜色相同
change(a, b);
}
}
//for (int i = 1; i <= n; i++) printf("%d", data[i]);
} int main(){ init();
work();
return ;
}

【BZOJ1483】【链表启发式合并】梦幻布丁的更多相关文章

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

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

  2. 【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并

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

  3. 【链表+启发式合并】Bzoj1483 [HNOI2009] 梦幻布丁

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

  4. BZOJ1483 [HNOI2009]梦幻布丁 【链表 + 启发式合并】

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

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

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

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

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

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

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

  8. 洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)

    题目链接 给出 \(n\) 个布丁,每个补丁都有其颜色.现在有 \(m\) 次操作,每次操作将第 \(x_i\) 种颜色全部变为第 \(y_i\) 种颜色. 操作中可能会插入询问,回答目前总共有多少段 ...

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

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

随机推荐

  1. c#后台验证

    #region 后台验证 panda /// 验证电话号码的主要代码如下: public bool IsTelephone(string str_telephone) { return System. ...

  2. codeforces --- 115A

    A. Party time limit per test 3 seconds memory limit per test 256 megabytes input standard input outp ...

  3. 局域网内通过UDP协议进行传输接受数据——AsyncUdpSocket

    在相同的局域网内,可以通过Udp协议进行数据的传输和接收,Udp协议与Http协议不同,Udp更加方便快捷,省去了很多步骤,但是也有很多传输问题,在局域网内小范围传输数据时Udp还是非常能够胜任的. ...

  4. JSON 数据的系统解析

    - (IBAction)jsonSystemButtonDidClicked:(UIButton *)sender { self.JSONArray = [NSMutableArray array]; ...

  5. Qt on Android: Qt Quick 之 Hello World 图文具体解释

    在上一篇文章,<Qt on Android:QML 语言基础>中,我们介绍了 QML 语言的语法,在最后我们遗留了一些问题没有展开,这篇呢,我们就正式開始撰写 Qt Quick 程序,而那 ...

  6. 在LaTeX里插入全页的pdf 分类: LaTex 2015-02-04 17:20 142人阅读 评论(0) 收藏

    要帮女友排版毕业论文,需要插入封面,省时省力的方法就是把学校给的Word封面保存成PDF然后插入到Latex文档中. 首先添加下面的宏: \usepackage[final]{pdfpages} 然后 ...

  7. jQuery支持mobile的全屏水平横向翻页效果

    这是一款支持移动手机mobile设备的jQuery全屏水平横向翻页效果插件. 该翻页插件能够使页面在水平方向上左右全屏翻动,它支持手机触摸屏,支持使用鼠标滚动页面. 整个页面过渡平滑,效果很不错. 在 ...

  8. 尝鲜basic开发android

    做过android开发的同学都知道,很大精力都需要去面对界面编程,这个是非常没效率非常痛苦的一件事.偶然得知basic老树发新芽,居然还可以做android开发,决定试试效果如何. 首先上:http: ...

  9. MS SQL 性能优化

    http://blog.csdn.net/dba_huangzj/article/details/50455543

  10. mysql 存储过程项目小结

    1. false :0  true 1 切记 官方文档:http://dev.mysql.com/doc/refman/5.0/en/numeric-type-overview.html BOOL,  ...