[HNOI2009]梦幻布丁

题目描述

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

输入描述

第一行给出N,M表示布丁的个数和好友的操作次数. 

第二行N个数A1,A2...An表示第i个布丁的颜色从

第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 

若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0

输出描述

针对第二类操作即询问,依次输出当前有多少段颜色.

示例一

输入

4 3
1 2 2 1
2
1 2 1
2

输出

3
1

说明
初始时布丁颜色依次为1,2,2,1,三段颜色分别为 [1, 1], [2, 3], [4, 4]。
一次操作后,布丁的颜色变为1,1,1,1,只有[1,4] 一段颜色。

解题思路

首先将相同颜色的布丁放在同一个数组里面,在放入布丁的同时进行判断,判断当前布丁颜色是否与前一个布丁颜色是一样的,如果不同,则段数加一。

当对布丁颜色进行改变时候,我们利用等效思想,将布丁数少的颜色换成布丁数多的颜色,再写一个change函数来模拟,改变颜色之后,分别将当前颜色段与前一段和后一段颜色比较,判断它们是否会相同,如果相同,段数减一。

模拟之后得到段数,再进行实际的颜色改变,将改变颜色后的布丁都加进相同颜色的布丁数组,再将颜色改变前的布丁数组清空。

实现代码

话不多说,上代码

#include<iostream>
#include<vector>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
#define rep(j,m) for(int j = 0;j < m;j++)

const int N=1e6+10,mod=1e9-7,INF=1e9+10;
int n,m;
int ans = 1;
int col[N];
vector<int> g[N];

void change(int a,int b){//颜色a和颜色b
    for(int i:g[a]){
        if(i-1 >= 0 and col[i-1] == b)ans--;//用于判断颜色发生变化之后,前后布丁颜色是否一致
        if(i+1 < n and col[i+1] == b)ans--;
    }

}

int main()
{
    cin >> n >> m;
    rep(i,n){
        cin >> col[i];
        g[col[i]].push_back(i);//将布丁的颜色存入对应的数组里面
        if(col[i] != col[i-1] and i > 0)ans++;//如果当前布丁颜色与前一个布丁颜色不一样,则ans++
    }
    int num = 0;//用于统计有多少种颜色
    rep(i,n){
        if(!g[i].empty())num++;
    }
    rep(j,m){
        int op;
        int x,y;
        cin >> op;
        if(op==1){
            cin >> x >>y;
            if(x == y)continue;//当变化前后布丁颜色相同,则不做出改变
            int a,b;
            if(g[x].size() > g[y].size()){//确保a存的都是布丁数较少的颜色,以此提高交换效率
                a = y;b = x;
            }else{
                a = x;b = y;
            }
            change(a,b);//将颜色x换为颜色y与颜色y换为x是等效的
            for(int i:g[x])col[i]=y;//进行交换操作
            g[y].insert(g[y].end(),g[x].begin(),g[x].end());//进行合并
            g[x].clear();//清空颜色x的布丁
        }
        if(op==2){
            cout << ans << endl;
        }
    }
    return 0;
}

希望大家都能顺利AC!!!

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值