【BZOJ1483】【HNOI2009】梦幻布丁
题意
N 个布丁摆成一行,进行M次操作.
每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.
例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.
题解
注意可能出现把a改成b后再改回来的情况
首先一个最简单的暴力就是每个颜色用一个vector保存位置,修改时把所有要修改的布丁暴力插入到目标颜色的vector里。
然后注意到可以用启发式优化,修改时把小的插到大的里。
可以开一个数组$dic$记录每个颜色的真实颜色,初始时$dic[i]=i$
如果目标颜色比修改颜色小,那么就$swap(dic[a],dic[b])$
修改前先$a=dic[a],b=dic[b]$
代码
#include <iostream> #include <cstdio> #include <vector> #include <stack> using namespace std; #define N 1000001 #define now q[a][i] int fa[N],col[N],dic[N]; bool vis[N]; vector<int> q[N]; int main() { int n,m,cnt; cin>>n>>m; cnt=n; for(int i=1;i<=n;i++) { scanf("%d",&col[i]); q[col[i]].push_back(i); if(col[i]==col[i-1]) cnt--; } for(int i=1;i<N;i++) dic[i]=i; for(int i=1;i<=m;i++) { int opt,a,b; scanf("%d",&opt); if(opt==1) { scanf("%d%d",&a,&b); if(a==b) continue; bool flag=(q[dic[a]].size()>q[dic[b]].size()); if(flag) swap(dic[a],dic[b]); a=dic[a],b=dic[b]; for(int i=0;i<q[a].size();i++) cnt-=(col[now-1]==b)+(col[now+1]==b);//减去颜色变化后连成一段的情况 for(int i=0;i<q[a].size();i++) { col[now]=b; q[b].push_back(now); } q[a].clear(); } else printf("%d\n", cnt); } }
看都看了,顺手点个推荐呗 :)