38.哀家要长脑子了!--离散化

1.802. 区间和 - AcWing题库

 妈呀。。感觉今天上午看了好久的这个终于摸清一点点了。。。

但是我又说不清楚整体的一个思路和逻辑TAT 我就先一步一步说我的看法

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

const int N = 1e5+10;  // n次插入和m次查询相关数据量的上界
int a[N];  // 存储坐标插入的值 我觉得可以理解为离散化后的数组
int s[N];  // 存储数组a的前缀和
vector<int> all;  // 存储(与插入和查询有关的)坐标 离散化后需要用到的坐标
vector<pair<int, int>> add, query;  // 存储插入和询问操作的数据 

// 二分查找 返回的是输入坐标的离散化下标
int find(int x){#include<bits/stdc++.h>
using namespace std;

const int N = 1e5+10;  // n次插入和m次查询相关数据量的上界
int a[N];  // 存储坐标插入的值 我觉得可以理解为离散化后的数组
int s[N];  // 存储数组a的前缀和
vector<int> alls;  // 存储(与插入和查询有关的)坐标 离散化后需要用到的坐标
vector<pair<int, int>> add, query;  // 存储插入和询问操作的数据 

// 二分查找 返回的是输入坐标的离散化下标
int find(int x){
    int l = 0, r = alls.size()-1;
    while(l < r) {
        int mid = l + r >> 1;
        if(alls[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return r + 1;
}

int main(){
    int n, m;
    cin >> n >> m;
    
    // n次插入
    for(int i = 1; i <= n; i++){
        int x, c;
        cin >> x >> c;  // 在坐标位置x上 加上数字c
        add.push_back({x, c});
        alls.push_back(x);
    }

    //m次询问区间和
    for(int i = 1; i <= m; i++){
        int l, r;
        cin >> l >> r;
        query.push_back({l, r});
        alls.push_back(l);
        alls.push_back(r);
    }

    // 对需要用到的坐标进行排序和去重
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());

    // 插入
    for(auto item : add){
        // 在数组alls里面找
        int x = find(item.first);
        a[x] += item.second;
    }

    // 前缀和
    for(int i = 1; i <= alls.size(); i++)
        s[i] = s[i-1] + a[i];

    // 询问区间和
    for(auto item : query){
        int l = find(item.first);
        int r = find(item.second);
        cout << s[r] - s[l-1] << endl;
    }
    
    return 0;
}
    int l = 0, r = alls.size()-1;
    while(l < r) {
        int mid = l + r >> 1;
            r = mid;
        else
            l = mid + 1;
    }
    return r + 1;
}

int main(){
    int n, m;
    cin >> n >> m;
    
    // n次插入
    for(int i = 1; i <= n; i++){
        cin >> x >> c;  // 在坐标位置x上 加上数字c
        add.push_back({x, c});
        alls.push_back(x);
    }

    //m次询问区间和
    for(int i = 1; i <= m; i++){
        cin >> l >> r;
        query.push_back({l, r});
        alls.push_back(l);
        alls.push_back(r);
    }

    // 对需要用到的坐标进行排序和去重
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());

    // 插入
    for(auto item : add){
        // 在数组alls里面找
        int x = find(item.first);
        a[x] += item.second;
    }

    // 前缀和
    for(int i = 1; i <= all.size(); i++)
        s[i] = s[i-1] + a[i];

    // 询问区间和
    for(auto item : query){
        int l = find(item.first);
        int r = find(item.second);
        cout << s[l] - s[r-1] << endl;
    }
    
    return 0;
}

可以想成下面这样:

arr[1] = 2  arr[3] = 6  arr[7] = 5

alls[0] = 1  alls[2] = 3 alls[3] = 7

要修改某个位置上的元素,很容易就想到用数组来做可以想象成哈希表

因为这个放数组的坐标位置范围很大,数组是存不完的。但是呢这个很大的数组又没有用到那么多 他们之间的数字很分散。

所以就需要用到离散化,使用一个新容器alls,这个里面的元素就是原来数组的下标

离散化就是把原来的索引映射到一个新的索引,达到缩小目标区间

实际处理的时候是没有arr的,而是直接把相关坐标存入alls中

参考:离散化(超详细)-CSDN博客

unique()函数

1.位于头文件<algorithm>中

2.作用:在一个范围内重新排列元素,使得每个重复的元素只出现一次,并且保持这些唯 

               一元素的相对顺序不变,不直接删除任何元素,而是通过移动操作将重复的元素移                 动到序列的某个末端位置,并返回一个指向最后一个唯一元素之后位置的迭代器

3.比较相邻元素:从序列的起始位置开始,将每个元素与其紧邻的前一个元素进行比较。这     里的比较默认使用==

4.移动重复元素:当发现两个相邻的元素相等,会将后面的重复元素向序列的末尾移动,覆     盖到它遇到的第一个重复元素(也就是不重复序列的最后一个元素的后一位)

举个例子:

a:[1, 2, 4, 2, 7, 2]

排序后:[1, 2, 2, 2, 4, 7]

去重的过程:[1, 2, 4, 2, 4, 7]

                      [1, 2, 4, 7, 4, 7] 

erase()函数

1.arr.erase(m):就是把 arr中第m+1个数字开始的,到结尾全部删除(包括m+1)

2.arr.erase(m, n):就是把 arr中第m+1个数字开始后面的n个数字全部删掉

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值