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 }