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

    bzoj1483[HNOI2009]梦幻布丁

    题意:

    N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色。

    题解:

    给每个颜色建一个链表。先预处理出答案,然后每次修改颜色时将两个链表合并,同时将修改后颜色对答案的贡献重新计算(如果两个节点的位置相差大于1说明中间有一段颜色,将贡献+1)。链表合并时用启发式合并(就是将小的拆了依次插入到大的里面),复杂度O(nlog2n)(均摊复杂度,玄学)。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define inc(i,j,k) for(int i=j;i<=k;i++)
     5 #define M 1000010
     6 #define N 100010
     7 using namespace std;
     8 
     9 int ans,head[M],last[N],next[N],comb[M],sz[M],n,m;
    10 int main(){
    11     scanf("%d",&n); scanf("%d",&m); int a,b=0; ans=0; 
    12     memset(sz,0,sizeof(sz)); memset(comb,0,sizeof(comb)); memset(head,0,sizeof(head));
    13     inc(i,1,n){
    14         scanf("%d",&a); if(a!=b)ans++,comb[a]++;
    15         next[i]=head[a]; last[head[a]]=i; head[a]=i; sz[a]++; b=a;
    16     }
    17     inc(i,1,m){
    18         int a1; scanf("%d",&a1); if(a1==2)printf("%d
    ",ans);
    19         if(a1==1){
    20             int a2,a3; scanf("%d%d",&a2,&a3); if(a2==a3)continue;
    21             if(head[a2]==0)continue; 
    22             else if(head[a3]==0)head[a3]=head[a2],sz[a3]=sz[a2],comb[a3]=comb[a2],head[a2]=sz[a2]=comb[a2]=0;
    23             else{
    24                 if(sz[a2]<sz[a3]){
    25                     int a4=head[a2],a6=head[a3]; 
    26                     while(a4){
    27                         int a5=next[a4];
    28                         for(;a4<a6&&next[a6]>0;a6=next[a6]);
    29                         if(a4<a6)next[a6]=a4,last[a4]=a6,next[a4]=0;
    30                         else if(last[a6]==0)last[a4]=0,next[a4]=a6,last[a6]=a4,head[a3]=a4;
    31                         else next[last[a6]]=a4,last[a4]=last[a6],next[a4]=a6,last[a6]=a4;
    32                         sz[a3]++; a4=a5;
    33                     }
    34                     sz[a2]=head[a2]=0;
    35                 }else{
    36                     int a4=head[a3],a6=head[a2]; 
    37                     while(a4){
    38                         int a5=next[a4];
    39                         for(;a4<a6&&next[a6]>0;a6=next[a6]);
    40                         if(a4<a6)next[a6]=a4,last[a4]=a6,next[a4]=0;
    41                         else if(last[a6]==0)last[a4]=0,next[a4]=a6,last[a6]=a4,head[a2]=a4;
    42                         else next[last[a6]]=a4,last[a4]=last[a6],next[a4]=a6,last[a6]=a4;
    43                         sz[a2]++; a4=a5;
    44                     }
    45                     head[a3]=head[a2],sz[a3]=sz[a2],head[a2]=sz[a2]=0;
    46                 }
    47                 ans-=comb[a2]; ans-=comb[a3]; comb[a2]=comb[a3]=0;
    48                 for(int i=head[a3];i;i=next[i])if(i==head[a3]||i!=last[i]-1)comb[a3]++;
    49                 ans+=comb[a3];
    50             }
    51         }
    52     }
    53     return 0;
    54 }

     

    20160320

  • 相关阅读:
    性能测试之-响应时间
    性能测试之-分类
    CSS 的基础语法
    linux之-mysql数据库约束3
    linux之-mysql数据库2
    linux安装mysql
    反向树状数组
    曼哈顿最小生成树
    最小生成树的性质
    CSA Round 84 Growing Trees
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5656750.html
Copyright © 2011-2022 走看看