1、题目大意:这题就是给你一个序列,有两个操作,一个是询问序列中的连续段数,比如序列 1 2 2 1就是三段。。
1是一段,2 2 又是一段,1又是一段,就是相同的在一起,第二个操作就是将其中的一种数全都改成另一种数
2、分析:这道题看起来做需要o(n^2),这是过不了的,我们需要nlogn的算法,怎么实现修改是均摊logn的呢。。
我们把两个链表合并是O(1)这个是一定的,但是修改答案是o(n)的对吧,那怎么办呢,
我们算修改答案把len小的合并到大的,仔细算算,其实算不了几次,这样就o(n),
我们还要存一个编号,就是一个数在链表里的编号
这样,我们就可以ac了
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; int h[2000000]; int num[2000000]; int head[2000000], ne[2000000]; int len[2000000]; int main(){ memset(head, -1, sizeof(head)); int n, m; scanf("%d%d", &n, &m); int ans = 0; for(int i = 1; i <= n; i ++){ scanf("%d", &h[i]); ne[i] = head[h[i]]; head[h[i]] = i; num[h[i]] = h[i]; if(h[i] != h[i - 1]) ans ++; len[h[i]] ++; } for(int i = 1; i <= m; i ++){ int op; scanf("%d", &op); if(op == 2) printf("%d\n", ans); else { int a, b; scanf("%d%d", &a, &b); if(a == b) continue; if(len[num[a]] > len[num[b]]) swap(num[a], num[b]); a = num[a]; b = num[b]; if(len[a] == 0) continue; for(int j = head[a]; j != -1; j = ne[j]){ if(h[j - 1] == b) ans --; if(h[j + 1] == b) ans --; } int p; for(int j = head[a]; j != -1; j = ne[j]){ h[j] = b; p = j; } ne[p] = head[b]; head[b] = head[a]; len[b] += len[a]; len[a] = 0; head[a] = -1; } } return 0; }