[HNOI2009]梦幻布丁

题目描述

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

输入输出格式

输入格式: 

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

输出格式:

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

输入输出样例

输入样例#1:
4 3
1 2 2 1
2
1 2 1
2
输出样例#1:
3
1

说明

1<=n,m<=100,000; 0<Ai,x,y<1,000,000

题解:

用链表+启发式合并

 

1:将两个队列合并,有若干队列,总长度为n,直接合并,最坏O(N),

 

2:启发式合并呢?

 

每次我们把短的合并到长的上面去,O(短的长度)

 

咋看之下没有多大区别,

 

下面让我们看看均摊的情况:

 

1:每次O(N)

 

2:每次合并后,队列长度一定大于等于原来短的长度的两倍。

 

这样相当于每次合并都会让短的长度扩大一倍以上,

 

最多扩大logN次,所以总复杂度O(NlogN),每次O(logN)。

这题很容易搞混,启发式合并可以这么想,把x换成y可以视为把y换成x,在当前不会对答案有影响

但之后就会换错颜色,所以从把x换成y变为把y换成x之后还要记下当前颜色的实际颜色(启发式合并做了交换)

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int nxt[1000001],head[1000001],color[1000001],set[1000001],size[1000001],ans,first[1000001],n,m;
 7 void solve(int x,int y)
 8 {int i;
 9     for (i=head[x];i;i=nxt[i])
10     {
11         if (y==color[i-1]) ans--;
12         if (y==color[i+1]) ans--;
13     }
14     for (i=head[x];i;i=nxt[i])
15     {
16         color[i]=y;
17     }
18     nxt[first[x]]=head[y];
19     head[y]=head[x];
20     size[y]+=size[x];
21     head[x]=size[x]=first[x]=0;
22 }
23 int main()
24 {int i,j,opt,x,y;
25    cin>>n>>m;
26    for (i=1;i<=n;i++)
27    {
28          scanf("%d",&color[i]);
29          if (color[i]!=color[i-1]) ans++;
30          set[color[i]]=color[i];
31          if (head[color[i]]==0) first[color[i]]=i;
32          size[color[i]]++;
33          nxt[i]=head[color[i]];
34          head[color[i]]=i;
35    }    
36     for (i=1;i<=m;i++)
37     {
38         scanf("%d",&opt);
39         if (opt==1)
40         {
41             scanf("%d%d",&x,&y);
42             if (x==y) continue;
43             if (size[set[x]]>size[set[y]]) swap(set[x],set[y]);
44             x=set[x];y=set[y];
45             if (size[x]==0) continue;
46             solve(x,y);
47         }
48         else 
49         {
50             printf("%d\n",ans);
51         }
52     }
53 }

 

posted @ 2017-07-31 12:59  Z-Y-Y-S  阅读(417)  评论(0编辑  收藏  举报