zoukankan      html  css  js  c++  java
  • bzoj 1483 [HNOI2009]梦幻布丁(链表+启发式合并)

    1483: [HNOI2009]梦幻布丁

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 1818  Solved: 761
    [Submit][Status][Discuss]

    Description

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

    Input

    第 一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表 示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0

    Output

    针对第二类操作即询问,依次输出当前有多少段颜色.

    Sample Input

    4 3
    1 2 2 1
    2
    1 2 1
    2

    Sample Output

    3
    1

    【思路】

           链表+启发式合并。

           每种颜色设一个链表,并记下段数ans。

           对于修改,先假设不变,如果左,右不一样则ans--,然后修改颜色值,再遍历一次,如果不一样则ans++,这样就只有因为颜色相同而并成一块的会ans—了。具体修改成哪一个颜色对题目并没有影响,所以采用启发式合并,每次将颜色数少的设为颜色数多的,合并后的总长度一定大于较短的两倍,我们每次都是操作较短的,每次合并长度都会扩大两倍以上最多扩大logn次,时间复杂度为O(nlogn)。

    【代码】

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 const int M = 1e6+100;
     7 
     8 int n,m,a[M],num[M],next[M],front[M],p[M],ans=0;
     9 
    10 int main() {
    11     scanf("%d%d",&n,&m);
    12     memset(front,-1,sizeof(front));
    13     for(int i=1;i<=n;i++){
    14         scanf("%d",&a[i]);
    15         num[a[i]]++;
    16     }
    17     for(int i=1;i<=n;i++){
    18         next[i]=front[a[i]];
    19         front[a[i]]=i;
    20     }
    21     for(int i=1;i<=n;i++)
    22         if(a[i]!=a[i-1]) ans++;
    23     for(int i=1;i<=M-1;i++) p[i]=i;
    24     for(int j=1;j<=m;j++) {
    25         int op,x,y;
    26         scanf("%d",&op);
    27         if(op==2)
    28             printf("%d
    ",ans);
    29         else {
    30             scanf("%d%d",&x,&y);
    31             if(x==y) continue;
    32             if(num[p[x]]>num[p[y]]) swap(p[x],p[y]);
    33             x=p[x]; y=p[y];
    34             if(num[x]==0) continue;
    35             for(int i=front[x];i!=-1;i=next[i]){
    36                 if(a[i]!=a[i-1]) ans--;
    37                 if(a[i]!=a[i+1]&&i!=n) ans--;
    38             }
    39             for(int i=front[x];i!=-1;i=next[i]) a[i]=y;
    40             int head;
    41             for(int i=front[x];i!=-1;i=next[i]) {
    42                 if(a[i]!=a[i-1]) ans++;
    43                 if(a[i]!=a[i+1]&&i!=n) ans++;
    44                 head=i;
    45             }
    46             num[y]+=num[x]; num[x]=0;
    47             next[head]=front[y]; front[y]=front[x];
    48             front[x]=-1;
    49         }
    50     }
    51     return 0;
    52 }
  • 相关阅读:
    【转】【SEE】基于SSE指令集的程序设计简介
    【转】【Asp.Net】asp.net服务器控件创建
    ControlTemplate in WPF ——ScrollBar
    ControlTemplate in WPF —— Menu
    ControlTemplate in WPF —— Expander
    ControlTemplate in WPF —— TreeView
    ControlTemplate in WPF —— ListBox
    ControlTemplate in WPF —— ComboBox
    ControlTemplate in WPF —— TextBox
    ControlTemplate in WPF —— RadioButton
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5193233.html
Copyright © 2011-2022 走看看