洛谷P3939 数颜色 vector乱搞

一道来自洛谷的题目,要求在长度不超过3e5的序列中支持查询区间内特定颜色的数量以及交换相邻元素的操作。通过使用vector来存储每个颜色出现的位置,利用二分查找可以达到O(log n)的时间复杂度解决查询问题。对于交换操作,先找到要交换元素的颜色,再更新vector中对应颜色的位置,最后交换序列中的元素。这题提醒我们在面对多类型操作时,要灵活选择合适的数据结构和算法。

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


洛谷P3939 数颜色


标签

  • vector乱搞

简明题意

  • 给一个序列(n <= 3e5),现需要你支持两种操作。
    1. 询问区间[L,R]中有多少个值为x的数
    2. 交换第k和k+1个数

思路

  • 首先,这题需要你统计数出现的个数,是不是主席数立马用上心头?但是对于交换操作,似乎不是那么容易~

  • 好吧,这题正解是可以vector二分乱搞的。我们先开一个vector<int> co[maxn]co[i]保存颜色i出现的所有位置,说到这里是不是豁然开朗呢?比如样例1 2 3 2 3 3 ,保存起来是这样的:

    1. co[1] = 1
    2. co[2] = 2,4
    3. co[3] = 3,5,6

    这时,我们想要查询2在[1,3]出现的次数,是不是只用在co[2]中查找有多少个数是在区间[1,3]中的呢?显然这里直接二分出1和3的位置,相减即是答案,复杂度是O(lg n)

  • 接下来是修改操作,例如修改k=3,我们只需要先找到3位置的颜色(多开一个数组a[i]记录每个位置的颜色),然后去co[a[3]]中二分到3,并使他++,同理处理co[a[4]]。最后呢,把交换a[i]和a[i + 1],就可以了。复杂度也是O(lg n)


注意事项


总结


  • 题目有的时候需要你支持多种操作。当我们仅用二分就能使得这些操作为O(lg n),这时就要考虑不要用那些高级数据结构了

AC代码

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 3e5 + 10;

int n, m, a[maxn];
vector<int> co[maxn];

void solve()
{
   scanf("%d%d", &n, &m);
   for (int i = 1; i <= n; i++)
   {
   	scanf("%d", &a[i]);

   	co[a[i]].push_back(i);
   }

   while (m--)
   {
   	int opt;
   	scanf("%d", &opt);

   	if (opt == 1)
   	{
   		int l, r, x;
   		scanf("%d%d%d", &l, &r, &x);

   		printf("%d\n", upper_bound(co[x].begin(), co[x].end(), r) - lower_bound(co[x].begin(), co[x].end(), l));
   	}
   	else
   	{
   		int x;
   		scanf("%d", &x);

   		(*lower_bound(co[a[x]].begin(), co[a[x]].end(), x))++;
   		(*lower_bound(co[a[x + 1]].begin(), co[a[x + 1]].end(), x + 1))--;
   		swap(a[x], a[x + 1]);
   	}
   }
}

int main()
{
   solve();
   return 0;
}

双倍经验

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值