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

    题意:N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.

    对每个颜色的位置维护链表。合并两个颜色,连接链表,统计贡献。

    统计贡献的复杂度是与链表长度有关的。如果遍历长度短的链表那么复杂度自然更小(遍历链表然后比较相邻元素的颜色)

    于是想到启发式合并,把小的合并到大的上

    每个元素只多被合并log次(因为每次合并后长度翻一倍)总复杂度nlogn

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=1e5+5,M=1e5+5,C=1e6+6;
    int n,m;
    int a[N];
    
    int h[C],ed[C],nex[N],f[C],cnt[C];
    int tot;
    
    void merge(int x,int y){//将两个链表连接
        for(int i=h[x];i;i=nex[i])tot-=(a[i-1]==y)+(a[i+1]==y);
        for(int i=h[x];i;i=nex[i])a[i]=y;
        nex[ed[x]]=h[y],h[y]=h[x],cnt[y]+=cnt[x];
        h[x]=ed[x]=cnt[x]=0;
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            tot+=a[i]!=a[i-1];
            if(!h[a[i]])ed[a[i]]=i;
            nex[i]=h[a[i]], h[a[i]]=i;
            f[a[i]]=a[i], cnt[a[i]]++;
        }
        for(int i=1;i<=m;i++){
            int op,x,y;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&x,&y);
                if(x==y)continue;
                if(cnt[f[x]]>cnt[f[y]])swap(f[x],f[y]);//交换颜色
                if(!cnt[f[x]])continue;//如果一个颜色不存在,那么就不用管了
                merge(f[x],f[y]);
            } else {
                printf("%d
    ",tot);
            }
        }
        return 0;
    }
    /*
     * BUG#1: L12L13不能圧成一行
     * BUG#2: L34没有用cnt
     * BUG#3: 合并的时侯把x合并到了y后面,又没有更新ed[y]emmm
     */
    
    
  • 相关阅读:
    CSS系列:长度单位&字体大小的关系em rem px
    CSS兼容性
    html5+css3
    将url的查询参数解析成字典对象
    SQL阻止保存要求重新创建表的更改 在哪里设置
    Jquery&JS简单选项卡
    块级&行内(内联)元素
    时间
    PHP 二维数组根据某个字段排序
    php 操作数组 (合并,拆分,追加,查找,删除等)
  • 原文地址:https://www.cnblogs.com/sshwy/p/10999419.html
Copyright © 2011-2022 走看看