【bzoj1483】【HNOI2009】梦幻布丁

1483: [HNOI2009]梦幻布丁

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 4092  Solved: 1674
[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。
n,m<=1000000

Output

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

 

题解:

     注意到:颜色一定是单调不增,段数一定是单调不增的,可以一边修改一边ans--;

          用链表维护每一个颜色的下标,启发式合并,每次取出较小的,如果某个位置的前面或后面原来不同改颜色后相同了就ans--;

          实现注意细节;

        

 1 #include<bits/stdc++.h>
 2 #define il inline 
 3 #define rg register 
 4 using namespace std;
 5 const int N=1000010;
 6 int n,m,hd[N],nt[N],ans,a[N],id[N],sz[N];
 7 il void adde(int x,int y){nt[y]=hd[x];hd[x]=y;sz[x]++;}
 8 void solve(int x,int y){
 9     for(int i=hd[x];i;i=nt[i]){
10         if(a[i-1]==y)ans--;
11         if(a[i+1]==y)ans--; 
12     }
13     for(int i=hd[x];i;){
14         int tmp=i; i=nt[i];
15         adde(y,tmp);
16         a[tmp]=y; 
17     } 
18     hd[x]=0;
19 }
20 int main(){
21 //  freopen("bzoj1483.in","r",stdin);
22 //  freopen("bzoj1483.out","w",stdout);
23     scanf("%d%d",&n,&m);
24     for(int i=1;i<=1e6;i++)id[i]=i;
25     for(rg int i=1;i<=n;i++){
26         scanf("%d",&a[i]);
27         adde(a[i],i);
28         if(a[i]!=a[i-1])ans++;
29     }
30     for(int i=1,op,x,y;i<=m;i++){
31         scanf("%d",&op);
32         if(op&1){
33             scanf("%d%d",&x,&y);
34             if(x==y)continue;
35             if(sz[x]>sz[y]){
36                 solve(id[y],id[x]); 
37                 swap(id[y],id[x]);
38             }else solve(id[x],id[y]);
39         }else printf("%d\n",ans);
40     }
41     return 0;
42 }
43 
bzoj1483

 

posted @ 2018-12-09 19:03  大米饼  阅读(242)  评论(0编辑  收藏  举报