版权声明:欢迎转载蒟蒻博客,但请注明出处:blog.csdn.net/lpa20020220 https://blog.csdn.net/LPA20020220/article/details/82494452
洛谷传送门
BZOJ传送门
题目描述
个布丁摆成一行,进行
次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1 2 2 1
的四个布丁一共有
段颜色.
输入输出格式
输入格式:
第一行给出 , 表示布丁的个数和好友的操作次数. 第二行 个数 表示第 个布丁的颜色从第三行起有 行,对于每个操作,若第一个数字是 表示要对颜色进行改变,其后的两个整数 表示将所有颜色为 的变为 , 可能等于 . 若第一个数字为 表示要进行询问当前有多少段颜色,这时你应该输出一个整数。
输出格式:
针对第二类操作即询问,依次输出当前有多少段颜色.
输入输出样例
输入样例#1:
4 3
1 2 2 1
2
1 2 1
2
输出样例#1:
3
1
说明
解题分析
将每种颜色的位置用链表串起来, 合并的时候启发式合并即可。
注意交换颜色。
总复杂度 。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int pre[MX * 10], col[MX], head[MX * 10], siz[MX * 10], ind[MX * 10];
int ans, dot, q;
IN void merge(int &x, int &y)
{
if(x == y) return;
if(siz[x] > siz[y]) std::swap(x, y); siz[y] += siz[x];
for (R int i = head[x]; i; i = pre[i])
ans -= (col[i - 1] == y) + (col[i + 1] == y);
for (R int i = head[x]; i; i = pre[i])
{
col[i] = y;
if(!pre[i]) {pre[i] = head[y], head[y] = head[x]; break;}
}
head[x] = 0; siz[x] = 0;
}
int main(void)
{
int typ, a, b;
in(dot), in(q);
for (R int i = 1; i <= dot; ++i) in(col[i]), pre[i] = head[col[i]], head[col[i]] = i, ++siz[col[i]];
for (R int i = 1; i <= dot; ++i) if(col[i] != col[i - 1]) ++ans;
for (R int i = 1; i <= 1000000; ++i) ind[i] = i;
W(q--)
{
in(typ);
if(!(typ & 1)) printf("%d\n", ans);
else in(a), in(b), merge(ind[a], ind[b]);
}
}