2022-05-27每日刷题打卡

2022-05-27每日刷题打卡

代码源——每日一题

题目背景

鶸尛鱻养了许多兔纸。

题目描述

众所周知,兔纸是一种神奇的生物,它有许多种毛色。

鶸尛鱻一共有 n 只兔纸,它们从左到右排成一排,第 i 只兔纸的毛色为 coli。

兔纸们十分活跃,时常会与旁边的兔纸交换位置。

五颜六色的兔纸弄得鶸尛鱻眼花缭乱,他想统计区间 [l,r] 内兔纸的颜色,但他的数学很差,你可以帮帮他吗?

输入格式

第 1 行两个正整数 n,m 分别表示兔纸数量和操作次数。

第 2 行 n 个正整数 col1,col2,…,coln,表示初始状态下从左到右每只兔纸的颜色。

此后 m 行,每行输入格式为 1 x 或 2 l r c,其中 {1/2} 表示操作类型。

操作 1 为 交换 操作,表示第 x 只兔纸和第 x+1 只兔纸交换位置。

操作 2 为 查询 操作,询问当前区间 [l,r] 内有多少只颜色为 c 的兔纸。

输出格式

对于每个操作 2,你需要输出一行一个自然数作为答案。

样例输入
7 9
8 7 6 6 7 8 3
1 5
1 4
2 1 7 7
1 6
1 4
2 3 6 8
2 1 3 7
2 1 2 6
2 2 5 7
样例输出
2
1
1
0
1
数据范围

对于全部测试数据,满足 2≤n≤3×105,1≤m,coli,c≤3×105,且保证 1≤x<n,1≤l<r≤n。

问题解析

一开始写的线段树,但是t了,后来看大佬做法发现vector或者普通二维数组就可以了。

按照颜色分类,一个颜色一个数组v,每个数组存的是这个颜色在原数组的下标。

操作1:我们先看原数组x和x+1这两个位置的颜色是否一样,如果一样就没必要换了,如果不一样,我们先根据x的颜色在数组v里找到他对应的元素,因为我们的元素存的是位置,x和x+1就相当于位于x的元素移动到x+1去了,那么我们把v数组里的对应元素++即可。然后找x+1,同理x+1移动到x去了,那么我们直接把v数组对应元素–即可。查找元素这两步可以用二分,如果用的vector写那就用自带的lower就可以,如果是普通数组就要手写二分了。

操作2:我们在颜色c的数组v里,二分找大小在lr的元素,找到多少个就说明lr区间有多少个颜色为c的元素。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6;
int a[N];
vector<int>v[N];

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        v[a[i]].push_back(i);
    }
    int st, l, r, c;
    while (m--)
    {
        cin >> st;
        if (st == 1)
        {
            cin >> c;
            if (a[c] == a[c + 1])continue;
            int x = lower_bound(v[a[c]].begin(), v[a[c]].end(), c) - v[a[c]].begin();
            v[a[c]][x]++;
            int y = lower_bound(v[a[c + 1]].begin(), v[a[c + 1]].end(), c + 1) - v[a[c + 1]].begin();
            v[a[c + 1]][y]--;
            swap(a[c], a[c + 1]);
        }
        else
        {
            cin >> l >> r >> c;
            int x = lower_bound(v[c].begin(), v[c].end(), l) - v[c].begin();
            int y = upper_bound(v[c].begin(), v[c].end(), r) - v[c].begin() - 1;
            if (x > y)cout << 0 << endl;
            else cout << y - x + 1 << endl;
        }
    }

    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值