博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
牛客网暑期ACM多校训练营(第一场)J Different Integers
阅读量:2125 次
发布时间:2019-04-30

本文共 3500 字,大约阅读时间需要 11 分钟。

题意

长度为N的数组,Q次询问,每次询问给两个数 L,R,求区间 [1, L] 和 [R, N]中一共有几种数

1 <= N, Q <= 1e5
每次最多10个测试数据

AC

  • 暴力肯定超时,用树状数组维护
    离线考虑没出现的数字个数假设 r > last[x],那么当l < first[x] 时,则x 没出现
    有两种实现方式:
    1. 按照查询区间的右端点升序
      当数字最后出现在这个右端点处,那么下面的区间的右侧至少不会出现这个数字,因为下个区间的右端点大于等于上个区间,只用判断左区间就ok
    2. 按照查询区间的左端点降序
      当数字第一次出现在左端点处,那么下一个区间的左侧至少不会出现这个数字,因为下个区间的左端点小于上个区间,只用判断右区间就ok
  • 左端点降序
using namespace std;struct ac{    int l, r, id;    bool operator <(const ac &x) {        return l > x.l;    }};int main() {#ifndef ONLINE_JUDGE    freopen("in.txt", "r", stdin);#endif    int n, q;    while (scanf("%d%d", &n, &q) != EOF) {        // 记录每个数 开始出现的位置 和 最后出现的位置        vector
a(n + 1), first(n + 1), last(n + 1); // 统计数字种类 int sum = 0; for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); last[a[i]] = i; if (!first[a[i]]) first[a[i]] = i, sum++; } // queries 存放询问 vector
queries(q); for (int i = 0; i < q; ++i) { scanf("%d%d", &queries[i].l, &queries[i].r); queries[i].id = i; } // 按照询问左区间降序 sort(queries.begin(), queries.end()); // count 记录不在范围中的数 // ans 记录每次询问的结果 vector
count(n + 1), ans(q); for (int i = n, k = 0; i >= 1; --i) { // 枚举每个区间 while (k < q && queries[k].l == i) { if (k == q) break; ans[queries[k].id] = sum; // 减去不在区间的数字, 向左枚举 for (int j = queries[k].r; j > 0; j -= lowbit(j)) { ans[queries[k].id] -= count[j]; } k++; } // 更新不在区间的数字 if (first[a[i]] == i) { for (int j = last[a[i]] + 1; j <= n; j += lowbit(j)) { count[j]++; } } } for (int i = 0; i < q; ++i) { printf("%d\n", ans[i]); } } return 0;}
  • 右端点升序
using namespace std;struct ac{    int l, r, id;    bool operator <(const ac &a) {        return r < a.r;    }};int main(){#ifndef ONLINE_JUDGE    freopen("in.txt", "r", stdin);#endif    int n, q;    while (~scanf("%d%d", &n, &q)) {        // 记录每个数 开始出现的位置 和 最后出现的位置        vector
a(n + 1), last(n + 1), first(n + 1); // 统计数字种类 int sum = 0; for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); last[a[i]] = i; if (!first[a[i]]) { first[a[i]] = i; sum++; } } // count 记录不在范围中的数 // ans 记录每次询问的结果 vector
count(n + 1), ans(q); // queries 存放询问 vector
queries(q); for (int i = 0; i < q; ++i) { scanf("%d%d", &queries[i].l, &queries[i].r); queries[i].id = i; } // 按照询问右端点升序 sort(queries.begin(), queries.end()); int k = 0; for (int i = 1; i <= n && k < q; ++i) { while (k < q && queries[k].r == i) { ans[queries[k].id] = sum; // 减去不在区间的数字, 向左枚举 for (int j = queries[k].l; j <= queries[k].r; j += lowbit(j)) { ans[queries[k].id] -= count[j]; } ++k; } // 更新不在区间的数字 if (last[a[i]] == i) { for (int j = first[a[i]] - 1; j > 0; j -= lowbit(j)) { count[j]++; } } } for (int i = 0 ; i < q; ++i) { printf("%d\n", ans[i]); } }

转载地址:http://xkprf.baihongyu.com/

你可能感兴趣的文章
Set、WeakSet、Map以及WeakMap结构基本知识点
查看>>
【NLP学习笔记】(一)Gensim基本使用方法
查看>>
【NLP学习笔记】(二)gensim使用之Topics and Transformations
查看>>
【深度学习】LSTM的架构及公式
查看>>
【深度学习】GRU的结构图及公式
查看>>
【python】re模块常用方法
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 21.包含min函数的栈
查看>>
剑指offer 23.从上往下打印二叉树
查看>>
剑指offer 25.二叉树中和为某一值的路径
查看>>
剑指offer 26. 数组中出现次数超过一半的数字
查看>>
剑指offer 27.二叉树的深度
查看>>
剑指offer 29.字符串的排列
查看>>
剑指offer 31.最小的k个树
查看>>
剑指offer 32.整数中1出现的次数
查看>>
剑指offer 33.第一个只出现一次的字符
查看>>
剑指offer 34.把数组排成最小的数
查看>>
剑指offer 35.数组中只出现一次的数字
查看>>
剑指offer 36.数字在排序数组中出现的次数
查看>>