WC2011mt特意强调了链表
其中就有这样一道题
Task pudding
【题目描述】
现在有 n 个布丁排成一排,每个布丁都有一个正整数颜色。
有 m 个操作:
第一种操作 1 x y 将所有颜色为 x 改为颜色 y。
第二种操作 2 询问当前有多少段颜色。
【输入数据】
第一行两个正整数 n,m。
下面一行,n 个正整数,表示一排的布丁。
下面 m 行,每行为一个操作。
【输出数据】
输出每组询问的答案。
【输入样例】
4 3
1 2 2 1
2
1 2 1
2
【输出样例】
3
1
【数据约定】
50% n,m <= 2000
100% n,m <= 100000,颜色均不超过 10^6
有关思想mt学长的解题报告讲的很清楚了
对于复杂度,尽管每次操作可能合并等长链表
但是利用启发式合并时复杂度均摊下来是logn的,m次操作 mlogn,是非常大的优化
code
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <memory>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int maxn = 1000000 + 5;
typedef int pint[maxn];
typedef unsigned int uint;
typedef long long int64;
typedef unsigned long long uint64;
template <class T> inline T Sqr(const T & x) { return x * x; }
template <class T> inline T Abs(const T & x) { return x > 0 ? x : -x; }
template <class T> inline T Min(const T & a, const T & b) { return a < b ? a : b; }
template <class T> inline T Max(const T & a, const T & b) { return a > b ? a : b; }
template <class T> inline T Ksm(const T & a, const T & b, const T & m) { T _ = 1; for (; b; b >>= 1, a = a * a % m) (b & 1) ? _ = _ * a % m : 0; return _ % m; }
template <class T> inline void Swap(T & a, T & b) { T _; _ = a; a = b; b = _; }
int n, m, tot;
pint col, t, f, next, edge;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 1; i <= maxn; ++i) f[i] = i;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &col[i]), ++t[col[i]];
next[i] = edge[col[i]], edge[col[i]] = i;
if (col[i] != col[i - 1]) ++tot;
}
for (int i = 1; i <= m; ++i)
{
int x, y, st, last;
if (scanf("%d", &st), st == 1)
{
if (scanf("%d%d", &x, &y), x == y) continue;
if (t[f[x]] > t[f[y]]) Swap(f[x], f[y]);
x = f[x]; y = f[y];
if (t[x] == 0 || t[y] == 0) continue;
for (int i = edge[x]; i; i = next[i])
{
if (col[i] != col[i - 1]) --tot;
if (i < n && col[i] != col[i + 1]) --tot;
}
for (int i = edge[x]; i; i = next[i]) col[i] = y;
for (int i = edge[x]; i; last = i, i = next[i])
{
if (col[i] != col[i - 1]) ++tot;
if (i < n && col[i] != col[i + 1]) ++tot;
}
int tmp = next[edge[y]]; next[edge[y]] = edge[x], next[last] = tmp;
t[y] += t[x]; t[x] = 0; edge[x] = 0;
}
else printf("%d\n", tot);
}
return 0;
}