zoukankan      html  css  js  c++  java
  • BZOJ1483 [HNOI2009]梦幻布丁

    题目描述:

    N个布丁摆成一行,进行M次操作.

    每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.

    例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.

    题解:

    链表加启发式合并。

    对每个颜色开个链表记录这个颜色每个布丁的位置,然后启发式合并链表,每次小的往大的合并,设小的链表大小x,

    每次合并复杂度是O(x),维护答案复杂度是O(x),合并后规模至少是2x,算一下复杂度就知道是O(nlogn)的怎么用启发式合并呢?

    要把链表长度小的接在链表长度大的后面,才能做到nlogn。因为把链表长度小的接在大的后面,新链表长度一定>=原长度小的链表的长度的两倍,

    最多变长logn次,所以均摊下来每次修改效率O(logn),总复杂度为O(nlogn)。

    那交换之后颜色换反了怎么办?

    记录一下每种颜色真实颜色是什么,如果一次染色是将一个大链表染向一个小链表,那就将两种颜色的真实颜色交换,仍然将小链表往大链表合并即可。

    附上代码:

    #include<cstdio>
    int n,m,a[100001],f[1000001],s[1000001],k,c,d,ans,head[1000001],next[1000001],l[1000001];
    void merge(int x,int y)
    {
        for(int i=head[x];i;i=next[i])
        {
            if(a[i+1]==y)
                ans--;
            if(a[i-1]==y)
                ans--;    
        }
        for(int i=head[x];i;i=next[i])
            a[i]=y;
        next[l[x]]=head[y];
        head[y]=head[x];
        s[y]+=s[x];
        s[x]=0;
        head[x]=0;
        l[x]=0;    
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            f[a[i]]=a[i];
            if(a[i]!=a[i-1])
                ans++;
            if(head[a[i]]==0)
                l[a[i]]=i;
            s[a[i]]++;
            next[i]=head[a[i]];
            head[a[i]]=i;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&k);
            if(k==1)
            {
                scanf("%d%d",&c,&d);
                if(c==d)
                    continue;
                if(s[f[c]]>s[f[d]])
                {
                    int z=f[d];
                    f[d]=f[c];
                    f[c]=z;
                }
                if(s[f[c]]==0)
                    continue;
                s[f[d]]+=s[f[c]];
                s[f[c]]=0;
                merge(f[c],f[d]);
            }
            else
                printf("%d
    ",ans);
        }    
        return 0;
    }
  • 相关阅读:
    [Linux系统] (3)应用安装方式详解(编译安装、rpm包安装、yum安装)
    [Linux系统] (2)用户权限管理
    jQuery.Validate验证库详解
    jQuery Ajax 实例 ($.ajax、$.post、$.get)
    原生js记住密码
    静态网站公用的部分模块的引用(设置)方法
    针对特定浏览器起作用的CSS: IE Chrome Firefox CSS Hack
    HTML5 video 视频标签全属性详解
    js for循环,为什么一定要加var定义i变量
    用谷歌浏览器来当手机模拟器
  • 原文地址:https://www.cnblogs.com/jiangminghong/p/9811343.html
Copyright © 2011-2022 走看看