首页 > 其他分享 >NC19427 换个角度思考

NC19427 换个角度思考

时间:2023-05-04 10:56:02浏览次数:50  
标签:偏序 NC19427 int sum 换个 leq 思考 维护 displaystyle

题目链接

题目

题目描述

给定一个序列,有多次询问,每次查询区间里小于等于某个数的元素的个数
即对于询问 \((l,r,x)\) ,你需要输出 \(\sum_{i=l}^{r}[a_i \le x]\) 的值
其中 \([exp]\) 是一个函数,它返回 \(1\) 当且仅当 \(exp\) 成立,其中 \(exp\) 表示某个表达式

输入描述

第一行两个整数 \(n,m\)
第二行 \(n\) 个整数表示序列 \(a\) 的元素,序列下标从 \(1\) 开始标号,保证 \(1 ≤ a_i ≤ 10^5\)
之后有 \(m\) 行,每行三个整数 \((l,r,k)\) ,保证 \(1 ≤ l ≤ r ≤ n\) ,且 \(1 ≤ k ≤ 10^5\)

输出描述

对于每一个询问,输出一个整数表示答案后回车

示例1

输入

5 1
1 2 3 4 5
1 5 3

输出

3

备注

数据范围
\(1 ≤ n ≤ 10^5\)
\(1 ≤ m ≤ 10^5\)

题解

知识点:树状数组,离线。

我们可以类比逆序对问题,求一个数 \(a_i\) 贡献的逆序对个数的公式 \(\displaystyle \sum_{j \leq i} [a_j > a_i]\) ,其中我们规定了 \(i\) 的枚举方向是从左到右,如此保证了 \(j\leq i\) 的偏序排除了干扰信息,再用数据结构维护 \([a_j > a_i]\) 的计算。同样的,我们可以把这个经典的公式变个形, \(\displaystyle \sum_{a_j > a_i} [j \leq i]\) ,也是同样可行的,我们从大到小枚举 \(a\) 保证 \(a_j > a_i\) 的偏序,再用数据结构维护 \([j \leq i]\) 的计算即可。

可以看出二维偏序问题中,离线将输入按照某偏序条件排序再枚举,等价于用了时间轴维护这个偏序,如此我们就可以使用线性数据结构(树状数组、线段树等)维护另一维偏序。

回到原问题,对于一个询问 \((l,r,x)\) 我们要计算 \(\displaystyle \sum_{i=l}^{r}[a_i \le x]\) ,我们可以转化为 \(\displaystyle \sum_{a_i \leq x} [l \leq i \leq r]\) 。我们可以利用时间轴维护 \(a_i < x\) 这个偏序,即将询问按 \(x\) 从小到大排序并枚举,随后用树状数组维护数字出现的区间查询即可。

但是显然,时间轴维护 \(l \leq i \leq r\) 不是那么显然,因为这不是单纯的一个偏序关系,其具有下界,需要维护数据的时效性。一个朴素的做法是带修莫队 \(O(n^{\frac{5}{3}})\) ,能过但很慢(我也不会qwq。另一个做法就是主席树,能天然维护这种关系(我更不会qwq。

时间复杂度 \(O((n+m) \log n + m \log m)\)

空间复杂度 \(O(n+m)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template<class T>
class Fenwick {
    int n;
    vector<T> node;

public:
    Fenwick(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        node.assign(n + 1, T());
    }

    void update(int x, T val) { for (int i = x;i <= n;i += i & -i) node[i] += val; }

    T query(int x) {
        T ans = T();
        for (int i = x;i;i -= i & -i) ans += node[i];
        return ans;
    }
    T query(int x, int y) {
        T ans = T();
        ans += query(y);
        ans -= query(x - 1);
        return ans;
    }
};

struct T {
    int sum = 0;
    T &operator+=(const T &x) { return sum += x.sum, *this; }
    T &operator-=(const T &x) { return sum -= x.sum, *this; }
};

pair<int, int> a[100007];

struct Query {
    int l, r, x, id;
}q[100007];

int ans[100007];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        int x;
        cin >> x;
        a[i] = { x,i };
    }
    for (int i = 1;i <= m;i++) {
        int l, r, x;
        cin >> l >> r >> x;
        q[i] = { l,r,x,i };
    }
    sort(a + 1, a + n + 1, [&](auto a, auto b) {return a.first < b.first;});
    sort(q + 1, q + m + 1, [&](auto a, auto b) {return a.x < b.x;});

    int pos = 1;
    Fenwick<T> fw(n);
    for (int i = 1;i <= m;i++) {
        while (pos <= n && a[pos].first <= q[i].x) {
            fw.update(a[pos].second, { 1 });
            pos++;
        }
        ans[q[i].id] = fw.query(q[i].l, q[i].r).sum;
    }

    for (int i = 1;i <= m;i++) cout << ans[i] << '\n';
    return 0;
}

标签:偏序,NC19427,int,sum,换个,leq,思考,维护,displaystyle
From: https://www.cnblogs.com/BlankYang/p/17370408.html

相关文章

  • 面向万物智联的应用框架的思考和探索(上)
     原文:https://mp.weixin.qq.com/s/G6o6xSAWroz0fJK7oShYLA,点击链接查看更多技术内容。 应用框架,是操作系统连接开发者生态,实现用户体验的关键基础设施。其中,开发效率和运行体验是永恒的诉求,业界也在持续不断的发展和演进。本文重点围绕移动应用框架,梳理其关键发展脉络,并分......
  • 关于Java栈与堆的思考
    关于Java栈与堆的思考2009-03-2821:00:02      2.栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译......
  • APP中弹窗统一管理的思考
    背景在项目的开发过程中,我们会碰到各种各样的弹窗,特别是启动的时候有许多弹窗都是需要显示的。在这种情况下,我们就需要对弹窗进行统一的管理,否则会出现弹窗重叠显示的问题,以及相互依赖的弹窗弹出的顺序不正确的问题或者同一弹窗会多次显示的问题。基于以上的原因,我们有必要对弹窗......
  • 关于线程安全的思考
    线程安全是什么?维基百科:线程安全是程序设计中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的公用变量,使程序功能正确完成。《Java并发编程实战(JavaConcurrencyInPractice)》的作者BrianGoetz:当多个线程同时访问一个对象时,如果不用考虑这些......
  • 12 BTC-思考
    《区块链技术与应用》课程链接:https://www.bilibili.com/video/BV1Vt411X7JF/?spm_id_from=333.337.search-card.all.click12BTC-思考目录12BTC-思考哈希指针,比特币很多设计使用了hash指针,指针保存的只是本机的内存地址,发送到其他计算机上就没有意义,那么,在发布区块的时候,h......
  • 如何避免单点风险:基于实践经验分享服务拆分原则的一些思考
    缘起:系统崩了具体情况:1%的请求影响了剩余90%的请求架构演进:拆分热点服务【进程级隔离】复盘总结拆服务的经典实践 不能变形的变形金刚也叫变形金刚?缘起系统崩溃了?别惊慌!这里有快速恢复的方法!分析发现,网站崩时服务X被流量打垮,继而依赖服务X的其它服务开始......
  • 关于为什么人会浪费时间的思考
    在一天内的工作后,人为什么宁愿玩游戏,刷抖音,也不愿意安安静静的休息呢?我觉得主要原因是需要缓解心理疲劳 如果一个人在一天的时间中,比较少获得正反馈.这样一天工作下来,心理会比较疲惫,需要一些正反馈来对冲自己的心理疲惫.无论是玩游戏,还是抖音,都可以给于一些正反馈......
  • 关于深度思考
    对任何领域要达到专家水平境界是一个非常困难的事情。对多数人而言,首要的是理解摆在他们面前的大量工作,并通过学习并获得直觉感悟,这些感悟促成了见识、格局的增长。自我境界(含见识、格局)的提升是一个漫长的过程,且是一个无法自我衡量的过程。但从大部分的生涯中总一下,其......
  • 数据在线迁移思考
    背景数据需要从一个库迁移到另外一个库,比如客户新买一个软件,使用的旧服务数据需要迁移到新软件内。或者数据压力较大,需要分库分表,数据需要迁移到新的库方案1双写开启双写可以在服务内增加配置,是否写新库、旧库。迁移期间,开启配置当天的数据同时写入新库和旧库。历史数......
  • PTA1006 换个格式输出整数(C++)
    一、问题描述:让我们用字母 B 来表示“百”、字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过3位的正整数。例如 234 应该被输出为 BBSSS1234,因为它有2个“百”、3个“十”、以及个位的4。输入格式:每个测试输入包含1个测......