Loading

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

http://www.lydsy.com/JudgeOnline/problem.php?id=1483

题意:中文。

思路:对于每一种颜色,用一个链表串起来,一开始保存一个答案,后面颜色替换的时候再更新答案。

那颜色应该如何替换呢:启发式合并

证明还没太懂。。。

又是一种新的暴力方法。我的理解大概就是对于两种相同的数据结构,如果有合并操作,那么将规模小的合并到规模大的上面,这样可以在O(nlogn)的时间复杂度下完成。

合并的时候将规模小的暴力更新,然后将小表接到大表上。

记得如果小的颜色链表长度为0,那么应该跳过,不然会出错的!!!

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 1000010
 4 int head[N], tail[N], mp[N], len[N], nxt[N], num[N], ans;
 5 
 6 void solve(int a, int b) {
 7     for(int i = head[a]; i; i = nxt[i]) {
 8         if(num[i+1] == b) ans--;
 9         if(num[i-1] == b) ans--;
10     }
11     for(int i = head[a]; i; i = nxt[i])  num[i] = b;
12     nxt[tail[a]] = head[b]; head[b] = head[a];
13     len[b] += len[a];
14     head[a] = tail[a] = len[a] = 0;
15 }
16 
17 int main() {
18     int n, m; scanf("%d%d", &n, &m);
19     for(int i = 1; i <= n; i++) {
20         scanf("%d", &num[i]);
21         if(!head[num[i]]) tail[num[i]] = i;
22         nxt[i] = head[num[i]]; head[num[i]] = i;
23         len[num[i]]++;
24         if(num[i] != num[i-1]) ans++;
25         mp[num[i]] = num[i];
26     }
27     while(m--) {
28         int kind, a, b;
29         scanf("%d", &kind);
30         if(kind == 2) {
31             printf("%d\n", ans);
32         } else {
33             scanf("%d%d", &a, &b);
34             if(a == b) continue;
35             if(len[mp[a]] > len[mp[b]]) swap(mp[a], mp[b]);
36             if(!len[mp[a]]) continue; // 一定要这句话
37             solve(mp[a], mp[b]);
38         }
39     }
40     return 0;
41 }

 

posted @ 2017-04-18 20:07  Shadowdsp  阅读(275)  评论(0编辑  收藏  举报