HH的项链(莫队/树状数组/主席树)

题目描述

HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。

有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入格式
一行一个正整数 n,表示项链长度。
第二行 n 个正整数 ai,表示项链中第 i 个贝壳的种类。

第三行一个整数 m,表示 H 询问的个数。
接下来 m 行,每行两个整数 l,r,表示询问的区间。

输出格式
输出 m 行,每行一个整数,依次表示询问对应的答案。

输入输出样例
输入 #1复制
6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出 #1复制
2
2
4

题解(莫队)

首先考虑莫队算法,离线操作,先对询问的l进行从小到大排序,相同的r如果在相同的块内,按照从小到大排序
莫队是一种离线暴力算法,采用的分块的思想,将询问的区间按照左端点和相同块内的右端点,从小到大排序,再用类似于双指针的操作,去左移右移区间来查询
代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#define int long long
#define gcd __gcd
#define endl '\n'
#define mem(x, y) memset(x, y, sizeof(x))
#define inf 0x3f3f3f
#define ninf 0xc0c0c0c0
#define y second
#define x first
#define FAST ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
typedef pair<int, int> PII;
const int M = 200010, N = 50010;
int t, len;
int a[N], cnt[(M * 10 << 1)], ans[M << 1];
int get(int i)
{
    return i / len;
}
struct node
{
    int l, r, i;
    bool operator<(const node &t) const
    {
        int a = get(l), b = get(t.l);
        if (a != b)
            return a < b;
        return r < t.r;
    }
} q[M << 1];

void add(int i, int &res)
{
    cnt[i]++;
    if (cnt[i] == 1)
        res++;
}
void del(int i, int &res)
{
    cnt[i]--;
    if (cnt[i] == 0)
        res--;
}
void solve()
{
    int n, m;
    cin >> n;
    len = sqrt(n);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    cin >> m;
    for (int i = 1; i <= m; i++)
    {
        cin >> q[i].l >> q[i].r;
        q[i].i = i;
    }
    sort(q + 1, q + m + 1);
    int res = 0, i = 0, j = 1;
    for (int k = 1; k <= m; k++)
    {
        int id = q[k].i, l = q[k].l, r = q[k].r;
        while (i < r) add(a[++i], res);
        while (i > r) del(a[i--], res);
        while (j < l) del(a[j++], res);
        while (j > l) add(a[--j], res);
        ans[id] = res;
    }
    for (int i = 1; i <= m; i++)
    {
        cout << ans[i] << "\n";
    }
}
signed main()
{
    FAST;
    solve();
}

题解(树状数组)

用树状数组的思想和莫队差不多,都是离线暴力,但是树状数组的时间复杂度更加优秀,首先把所有的询问储存进来,按找右端点从小到大进行排序后;
先不把值存进树状数组里,我们先定义一个pos,作为树状数组的下标,代表我们已经维护到了pos的位置,每次查询都更新到询问的r值,定义一个标记数组存每个数字最后一次出现的下标,每次先加上现在这个值的贡献,如果之前已经存在这个值了,再把这个值的贡献减掉,更新标记数组的值

#include <bits/stdc++.h>
#define ll long long
#define gcd __gcd
#define endl '\n'
#define mem(x, y) memset(x, y, sizeof(x))
#define inf 0x3f3f3f
#define ninf 0xc0c0c0c0
#define se second
#define fr first
using namespace std;
typedef pair<int, int> PII;
const int N = 1000010;
int a[N];
int c[N];
int n, m;
struct node
{
    int l, r, id;
    bool operator<(const node &t) const
    {
        if (r == t.r)
            return l < t.l;
        else
            return r < t.r;
    }
} q[N];
int lowbit(int x) { return x & -x; }

void add(int i, int x)
{
    for (; i <= n; i += lowbit(i))
        c[i] += x;
}
int ask(int i)
{
    int sum = 0;
    for (; i > 0; i -= lowbit(i))
        sum += c[i];
    return sum;
}

map<int, int> p;
int ans[N];
void solve()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; i++)
    {
        int l, r, id;
        scanf("%d%d", &l, &r);
        q[i] = {l, r, i};
    }
    sort(q + 1, q + m + 1);
    int pos = 0;
    for (int i = 1; i <= m; i++)
    {
        int l = q[i].l, r = q[i].r, idx = q[i].id;
        while (pos + 1 <= r)
        {
            pos++;
            add(pos, 1);
            if (p[a[pos]])
                add(p[a[pos]], -1);
            p[a[pos]] = pos;
        }
        ans[idx] = ask(r) - ask(l - 1);
    }
    for (int i = 1; i <= m; i++)
    {
        printf("%d\n", ans[i]);
    }
}
signed main()
{
    solve();
}

题解(主席树)

后续更新。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
{'体育': 0, '数字化': 1, '文化旅游': 2, '新能源': 3, '旅游': 4, '轨道交通': 5, '中医药': 6, '物联网': 7, '大数据': 8, '新一代信息技术': 9, '互联网+': 10, '人工智能': 11, '区块链': 12, '数字经济': 13, '生命': 14} Requirement already satisfied: matplotlib in /Users/hh/anaconda3/lib/python3.10/site-packages (3.7.0) Requirement already satisfied: cycler>=0.10 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (0.11.0) Requirement already satisfied: contourpy>=1.0.1 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (1.0.5) Requirement already satisfied: fonttools>=4.22.0 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (4.25.0) Requirement already satisfied: packaging>=20.0 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (22.0) Requirement already satisfied: pyparsing>=2.3.1 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (3.0.9) Requirement already satisfied: kiwisolver>=1.0.1 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (1.4.4) Requirement already satisfied: python-dateutil>=2.7 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (2.8.2) Requirement already satisfied: numpy>=1.20 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (1.23.5) Requirement already satisfied: pillow>=6.2.0 in /Users/hh/anaconda3/lib/python3.10/site-packages (from matplotlib) (9.4.0) Requirement already satisfied: six>=1.5 in /Users/hh/anaconda3/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)
最新发布
07-15

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值