1483: [HNOI2009]梦幻布丁

题目链接

题目大意:维护数列,兹瓷两种操作:1.把所有x变成y
2.询问数列中的连续段数,相邻且相同的为一段

题解:先求一下初始的答案,记作ans,然后维护它

由于没有数据范围,考虑用平衡树启发式合并暴力

用若干个链表维护,一个链表维护一种颜色出现的各个位置

操作1:启发式合并链表,同时维护答案

便sizep[i]i,p[i]=ip[x],p[y]

操作2:输出ans……

这里的多个链表使用前向星实现……

我终于会链表了

我的收获:求初始答案然后维护似乎挺常见的

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define M 1000100

int n,q,z,ans,t;
int c[M],sz[M],head[M],p[M];

struct edge{int to,nex;}e[M<<1];

void add(int u,int v){e[t]=(edge){v,head[u]};head[u]=t++;}

void merge(int x,int y)
{
    if(x==y) return ;//!!! 
    if(sz[p[x]]>sz[p[y]]) swap(p[x],p[y]);
    x=p[x];y=p[y];
    if(!sz[x]) return ;//!!!
    for(int i=head[x];i!=-1;i=e[i].nex){
        if(c[e[i].to-1]==y) ans--;//维护相邻位置对答案的影响 
        if(c[e[i].to+1]==y) ans--; 
    }
    for(int i=head[x];i!=-1;i=e[i].nex) c[e[i].to]=y;//修改 
    for(z=head[x];e[z].nex!=-1;z=e[z].nex);//找到链表x 
    e[z].nex=head[y];head[y]=head[x];head[x]=-1;//因为链表不需要考虑单调性,直接把链表y连到链表x后面 
    sz[y]+=sz[x];sz[x]=0;
}

void work()
{
    int opt,x,y;
    while(q--)
    {
        scanf("%d",&opt);
        if(opt==1) scanf("%d%d",&x,&y),merge(x,y);
        else printf("%d\n",ans);
    }
}

void init()
{
    t=0,memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
        if(c[i]!=c[i-1]) ans++;
        sz[c[i]]++;p[c[i]]=c[i];
        add(c[i],i);//用链表记录每个c[i]的位置 
    }
}

int main()
{
    init();
    work();
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值