【bzoj1483】【HNOI2009】梦幻布丁
1483: [HNOI2009]梦幻布丁
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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