[bzoj1483]:[HNOI2009]梦幻布丁

针对布丁颜色变换问题,采用启发式合并算法实现高效的颜色更新与颜色段计数。通过链表维护每种颜色布丁的位置关系,实现颜色变化后的快速更新及颜色段数量计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

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

n,m<=10^5 ai<=10^6

 

第一眼觉得可以平衡树+启发式合并

但是想了想直接启发式合并就行了  用链表链起来即可。

复杂度最坏nlogn

#include<iostream>
#include<cstdio>
#define rint register int
#define MN 100000
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9')  ch = getchar();
    while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0',ch = getchar();
    return x;
}

int n,m,ans=1,a[MN+5],head[MN*10+5],s[MN*10+5],size[MN*10+5],cnt=0;
struct edge{int x,next;}e[MN*35+5];
inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}

inline void Merge(int x,int y)
{
    x=s[x];y=s[y];size[y]+=size[x];
    for(rint i=head[x];i;i=e[i].next)    
        ans-=(e[i].x!=1&&a[e[i].x-1]==y)+(e[i].x!=n&&a[e[i].x+1]==y);
    for(rint i=head[x];i;i=e[i].next)
        ins(y,e[i].x),a[e[i].x]=y;
    head[x]=size[x]=0;
}

int main()
{
    n=read();m=read();
    for(rint i=1;i<=n;++i) a[i]=read(),s[a[i]]=a[i];
    for(rint i=1;i<=n;++i) ++size[a[i]],ins(a[i],i),ans+=(i!=1&&a[i]!=a[i-1]);
    for(rint i=1;i<=m;++i)
    {
        int op=read();
        if(op==1) 
        {
            int x=read(),y=read();if(x==y) continue;
            if(size[s[x]]>size[s[y]]) swap(s[x],s[y]);
            Merge(x,y);s[x]=0;
        }
        else printf("%d\n",ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/FallDream/p/bzoj1483.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值