BZOJ1483——[HNOI2009]梦幻布丁

来源:互联网 发布:车辆优化调度问题 编辑:程序博客网 时间:2024/04/29 15:27
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;} 


0 0
原创粉丝点击