P3201 [HNOI2009] 梦幻布丁 启发式合并

思路:
把相同颜色的用链表串起来,然后求一下最初值的贡献,然后进行启发式合并,将长度小的颜色的链合并到大的链表上,时间复杂度 n l o g n nlogn nlogn

参考代码:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
const int mod = 1000000007;
void read(int& v) {
    
    
  int k = 1;
  v = 0;
  int c = getchar();
  while (c < '0' || c > '9') {
    
    
    if (c == '-')
      k = 0;
    c = getchar();
  }
  while (c >= '0' && c <= '9')
    v = (v << 3) + (v << 1) + (c - 48), c = getchar();
  if (k == 0)
    v = -v;
}
int st[maxn], f[maxn], nxt[maxn], hd[maxn], sz[maxn], c[maxn];
int ans;
void merge(int x, int y) {
    
    
  for (int i = hd[x]; i; i = nxt[i])
    ans -= (c[i - 1] == y) + (c[i + 1] == y);
  for (int i = hd[x]; i; i = nxt[i])
    c[i] = y;
  nxt[st[x]] = hd[y], hd[y] = hd[x], sz[y] += sz[x];
  hd[x] = sz[x] = st[x] = 0;
}
int main() {
    
    
  int n, m;
  read(n), read(m);
  for (int i = 1; i <= n; i++) {
    
    
    read(c[i]), f[c[i]] = c[i];
    ans += (c[i] != c[i - 1]);
    if (!hd[c[i]])
      st[c[i]] = i;
    sz[c[i]]++, nxt[i] = hd[c[i]], hd[c[i]] = i;
  }
  for (int i = 0; i < m; i++) {
    
    
    int opt, x, y;
    read(opt);
    if (opt == 1) {
    
    
      read(x), read(y);
      if ((x == y))
        continue;
      if (sz[f[x]] > sz[f[y]])
        swap(f[x], f[y]);
      if (!sz[f[x]])
        continue;
      merge(f[x], f[y]);
    } else {
    
    
      printf("%d\n", ans);
    }
  }
}

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/109564458