Acwing802.区间和问题

题目描述

假定有一个无限长的数轴,数轴上每个坐标上的数都是 00。

现在,我们首先进行 nn 次操作,每次操作将某一位置 xx 上的数加 cc。

接下来,进行 mm 次询问,每个询问包含两个整数 ll 和 rr,你需要求出在区间 [l,r][l,r] 之间的所有数的和。

输入格式

第一行包含两个整数 nn 和 mm。

接下来 nn 行,每行包含两个整数 xx 和 cc。

再接下来 mm 行,每行包含两个整数 ll 和 rr。

输出格式

共 mm 行,每行输出一个询问中所求的区间内数字和。

数据范围

思路

1.前缀和:

区间和是典型的前缀和问题。

(1)建立一个sum数组,记录该元素以前(包括该元素)的所有值之和

(2)若要计算一个区间的长度,直接使用前缀和之差即可。

2.离散化:

由于该问题的数据范围>>操作个数,数据分布较为离散,若仅仅使用前缀和算法的计算复杂度较高。所以我们需要对要操作的数进行离散化

(1)读入所有加入的位置和查找的左右边界,放入a数组中。a数组记录所有可能会用到的下标

(2)对a数组的所有元素进行排序+去重。

(3)a中元素对应的下标即为前缀和数组对应下标。需要使用二分查找方法来将前缀和数组下标和目标区间的上下界进行查找(对应)

3.使用的数据结构:

(1)使用pair形式存储单个操作的[下标,值]、单次计算的[下界,上界];使用vector存储所有的操作和计算数据,vector中的每一个元素是一个pair

(2)使用一维数组(vector)的形式存储前缀和、使用到的下标。

代码:

#include <iostream>
#include <vector>
#include <algorithm>
#define N 300010

using namespace std;

int find(vector<int> a, int x){
    int left = 0, right = a.size()-1;
    int mid;
    while(left <= right){
        mid = left + (right - left)/2;
        if(a[mid] == x) return mid;
        else if(x < a[mid]) right = mid - 1;
        else left = mid + 1;
    }
    return right;
}


int main(){
    vector<int>a; //所有用到的下标
    vector<pair<int,int>> add, check;
    int n,m;
    cin >> n >> m;
    
    //1.插入元素的插入
    for(int i = 0; i < n; i ++ ){
        int x,c;
        cin>>x>>c;
        add.push_back({x,c});
        a.push_back(x);
    }
    
    //2.查询元素的插入
    for(int i = 0; i < m; i ++ ){
        int l,r;
        cin>>l>>r;
        a.push_back(l);
        a.push_back(r);
        check.push_back({l,r});
    }
    
    //3.去重
    sort(a.begin(),a.end());
    a.erase(unique(a.begin(),a.end()), a.end());//排序后删除重复元素

    
    //4.插入操作
    int value[N] = {0};
    for(auto &it : add){
        int pos = find(a, it.first);
        value[pos] += it.second;
    }
    
    //5.计算前缀和
    int sum[N] = {0};
    for(int i = 1; i <= a.size(); i++){
        sum[i] = sum[i - 1] + value[i - 1];
    }
    
    //6.计算结果并输出
    for(auto & it : check){
        int left = find(a, it.first);
        int right = find(a, it.second);
        int result = sum[right + 1] - sum[left];
        cout<<result<<endl;
    }
    
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
堆排序是一种高效的排序算法,它利用了堆的数据结构来实现排序。堆是一个完全二叉树,具有以下性质:对于任意节点 i,其父节点的值小于等于子节点的值。 堆排序的基本思路如下: 1. 构建最大堆:将待排序的数组看作是一个完全二叉树,从最后一个非叶子节点开始,依次向上调整每个节点,使得以该节点为根的子树满足最大堆的性质。 2. 将堆顶元素与最后一个元素交换:将最大堆的堆顶元素(即数组的第一个元素)与数组最后一个元素交换位置,此时最大元素就位于数组的最后。 3. 调整堆:将剩余元素重新调整为最大堆。 4. 重复步骤 2 和步骤 3,直到所有元素都排序完成。 以下是堆排序的 C++ 代码实现: ```cpp #include <iostream> using namespace std; // 调整以 root 为根的子树为最大堆 void heapify(int arr[], int n, int root) { int largest = root; // 假设根节点最大 int left = 2 * root + 1; // 左子节点索引 int right = 2 * root + 2; // 右子节点索引 // 若左子节点大于根节点,更新最大值索引 if (left < n && arr[left] > arr[largest]) { largest = left; } // 若右子节点大于最大值节点,更新最大值索引 if (right < n && arr[right] > arr[largest]) { largest = right; } // 若最大值不是根节点,交换根节点和最大值 if (largest != root) { swap(arr[root], arr[largest]); // 递归调整交换后的子树 heapify(arr, n, largest); } } void heapSort(int arr[], int n) { // 构建最大堆 for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } // 逐步取出最大值,调整堆 for (int i = n - 1; i > 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); } } int main() { int arr[] = {4, 10, 3, 5, 1}; int n = sizeof(arr) / sizeof(arr[0]); heapSort(arr, n); cout << "Sorted array: "; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; } ``` 以上就是堆排序的基本思路和实现方法。堆排序的时间复杂度为 O(nlogn),其中 n 为数组的长度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值