首页 > 代码库 > Bzoj1483 [HNOI2009]梦幻布丁
Bzoj1483 [HNOI2009]梦幻布丁
Submit: 2655 Solved: 1063
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
1 2 2 1
2
1 2 1
2
Sample Output
3
1
1
HINT
1<=n,m<=100,000; 0<Ai,x,y<1,000,000
Source
看到数据范围比较怂,然而看到题解都是用挺暴力的方法刚过去的。想了想好像有点道理。
链表+启发式合并
用链表存储每种颜色的所有布丁的位置,每次修改时,合并链表和颜色标记,记录链表长度,暴力修改长度较小的那个链表。
然而写挂了。向题解低头之后发现没有记录布丁原来的颜色,导致染色出了偏差。
↓注意37和38行的语句差别。要根据原色判断是否该染。
1 #include<algorithm> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 using namespace std; 6 const int mxn=2000100; 7 int read(){ 8 int x=0,f=1;char ch=getchar(); 9 while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}10 while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}11 return x*f;12 }13 int n,m;14 int hd[mxn],nxt[mxn],cnt[mxn];15 int now[mxn];16 int co[mxn];17 int main()18 {19 int i,j;20 n=read();m=read();21 int ans=0;22 for(i=1;i<=n;i++){23 co[i]=read();24 cnt[co[i]]++;25 nxt[i]=hd[co[i]];26 now[co[i]]=co[i];27 hd[co[i]]=i;28 if(co[i]!=co[i-1])ans++;29 }30 int x,y;31 for(i=1;i<=m;i++){32 x=read();33 if(x==2){printf("%d\n",ans);}34 else{35 x=read();y=read();36 if(x==y)continue;37 // if(cnt[x]>cnt[y])swap(x,y);38 if(cnt[now[x]]>cnt[now[y]])swap(now[x],now[y]);39 x=now[x];y=now[y];//原色 40 if(!cnt[x])continue;41 int last=0;42 for(j=hd[x];j;j=nxt[j]){43 if(co[j-1]==y)ans--;44 if(co[j+1]==y)ans--;45 last=j;46 }47 for(j=hd[x];j;j=nxt[j]){48 co[j]=y;49 }50 nxt[last]=hd[y];51 hd[y]=hd[x];52 hd[x]=0;53 cnt[y]+=cnt[x];54 cnt[x]=0;55 }56 }57 return 0;58 }
Bzoj1483 [HNOI2009]梦幻布丁
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。