BZOJ 1483: [HNOI2009]梦幻布丁(链表+启发式合并)

本文介绍了一种利用启发式合并策略优化颜色更改的问题解决方法。通过构建链表存储相同颜色的元素,并采用启发式合并减少操作次数,实现高效的颜色更新。文章详细解释了算法流程及其实现细节。

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

http://www.lydsy.com/JudgeOnline/problem.php?id=1483

题意:

 

思路:
每次修改的话需要把同一种颜色的都修改了,那如果去遍历的话就复杂度比较高,如果用链表把颜色相同的连接起来的话那么修改起来就十分方便了。

但是当两个链表需要合并的时候,修改长度短的那一个相对来说会比较省时,这就是启发式合并。但是使用启发式合并的话需要注意,如果现在有操作1->2,本来是要将所有的1改成2,如果1的链表长度大于2的链表长度的话,启发式合并就会将2合并至1,此时也就变成了将2变成1,所以我们需要一个数组pos来记录所要找的颜色在链表中实际对应的颜色。

那么当修改颜色时怎么动态维护答案呢,我们只需要扫描一遍链表,如果此时是x->y,如果颜色为x的某个数左边为y,那么ans--,右边为y,那么ans--。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<stack>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 #include<set>
11 using namespace std;
12 typedef long long ll;
13 typedef pair<int,int> pll;
14 const int INF = 0x3f3f3f3f;
15 const int maxn = 1000000+5;
16 
17 int n, m;
18 int a[maxn],sz[maxn],nxt[maxn],frt[maxn],pos[maxn];
19 
20 int main()
21 {
22    //freopen("in.txt","r",stdin);
23    scanf("%d%d",&n,&m);
24    int ans = 0;
25    for(int i=1;i<=n;i++)
26    {
27        scanf("%d",&a[i]);
28        if(a[i]!=a[i-1])  ans++;
29        sz[a[i]]++;
30        pos[a[i]]=a[i];
31        nxt[i]=frt[a[i]],frt[a[i]]=i;
32    }
33    while(m--)
34    {
35        int op;
36        scanf("%d",&op);
37        if(op==1)
38        {
39            int x,y,num;
40            scanf("%d%d",&x,&y);
41            if(x==y)  continue;
42            if(sz[pos[x]]>sz[pos[y]])  swap(pos[x],pos[y]);
43            x=pos[x],y=pos[y];
44            if(!sz[x])  continue;
45            for(int i=frt[x];i;i=nxt[i])
46            {
47                if(a[i+1]==y)  ans--;
48                if(a[i-1]==y)  ans--;
49                num = i;
50            }
51            for(int i=frt[x];i;i=nxt[i])  a[i]=y;
52            sz[y]+=sz[x],sz[x]=0;
53            nxt[num]=frt[y];
54            frt[y] = frt[x];
55            frt[x] = 0;
56        }
57        else printf("%d\n",ans);
58    }
59    return 0;
60 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/7806637.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值