HYSBZ 1483 梦幻布丁

HYSBZ 1483 梦幻布丁

模拟链表,链表启发式合并

题意

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

思路

暴力建出布丁的链表,记录每种颜色的起始位置,结束位置。

合并时将一个颜色的链表遍历,全改成另一种颜色,统计对ans的影响。并将链表连起来。

为了防止退化,统计出每个颜色的size,进行启发式合并。nc数组是记录某颜色实际的位置用的。

所以对于这道题,我们先将初始的答案处理出来,考虑将一个颜色全部暴力修改为另一种颜色之后对答案的影响,就是如果这个位置左面或者右面和目标颜色相同,ans- -。
但是由于我们要启发式合并,有可能交换两个颜色,这里有个小问题需要处理,如果我们要将颜色1变为颜色2,但是由于启发式合并颜色2并到了颜色1上,以后找颜色2时我们应该找颜色1,怎么办呢…
处理办法就是用一个nc[i]数组(nowcolor…)记录i颜色当前是是什么颜色,遇到要交换的情况时就swap(nc[a],nc[b]);

代码

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=2000007;
int c[MAXN], sz[MAXN], nc[MAXN];
int he[MAXN], ta[MAXN], ne[MAXN];
int ans;
void merge(int a, int b)
{
    if(sz[a]==0) return;
    for(int i=he[a];~i;i=ne[i])
    {
        if(c[i-1]==b) ans--;
        if(c[i+1]==b) ans--;
    }
    for(int i=he[a];~i;i=ne[i])
    {
        c[i]=b;
    }
    ne[ta[b]]=he[a];ta[b]=ta[a];
    sz[b]+=sz[a];sz[a]=0;
    he[a]=ta[a]=-1;
}
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m)==2)
    {
        M(he, -1), M(ta, -1), M(ne, -1);M(sz, 0);
        ans=0;
        for(int i=1;i<=n;i++)
        {
            int tmp;
            scanf("%d", &tmp);
            c[i]=tmp;
            if(ta[tmp]==-1) ta[tmp]=i;
            ne[i]=he[tmp];
            he[tmp]=i;
            if(c[i]!=c[i-1]) ans++;
            nc[tmp]=tmp;
            sz[tmp]++;
        }
        for(int i=1;i<=m;i++)
        {
            int op;scanf("%d", &op);
            if(op==1)
            {
                int c1, c2;scanf("%d%d", &c1, &c2);
                if(c1==c2) continue;
                else
                {
                    if(sz[nc[c1]]>sz[nc[c2]])
                        swap(nc[c1], nc[c2]);
                    merge(nc[c1], nc[c2]);
                }
            }
            else
            {
                printf("%d\n", ans);
            }
        }
    }
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值