zoukankan      html  css  js  c++  java
  • 离散化(AcWing.802)

    题目描述
    首先明确一下题意,先输入两个整数n、m,n代表在区间[-1e9,1e9]某一点加一个整数的次数,输入x c在x处加上c,m代表求某个区间和的次数,输入l r求区间[l,r]的和。

    分析
    分析一下y总的代码。

    主要分为5大步:
    1.读输入。将每次读入的x c push_back()到add中,将每次读入的位置x push_back()到alls中,将每次读入的l r push_back()到query中。
    2.排序、去重。
    3.通过遍历add,完成在离散化的数组映射到的a数组中进行加上c的操作(用到find函数)。
    4.初始化s数组。
    5.通过遍历query,完成求区间[l,r]的和。

    问题
    1.为什么要在alls中需要alls.push_back(l);alls.push_back(r);?

    首先要明确alls中存放的是位置而不是值,也就是存放的是x而不是c。

    因为再求区间和的时候,我们提前分析到可以使用前缀和来做,求前缀和就需要下标l r,如果不加入l r到alls中的话,第5步中遍历时query就没有办法通过输入的l r去访问a或者s。因为find函数就是输入映射前的下标,返回在alls中的下标+1。

    举个例子,拿平时的数组来说,下标都是整形,但是如果要求a[1.5]肯定是有错误的,在这里也一样。

    2.为什么要排序和去重?

    首先要明确find函数的功能,输入一个离散数组的位置(映射前的位置)x返回连续数组的位置+1(映射后的位置+1)。+1的目的是为了求区间和时少一步下标为0的判断。

    排序很好理解,因为在find函数中是使用了二分来查找x在alls中的下标+1,想要使用二分alls就必须具有某种性质这里就可以找一个最简单的办法使他单调(但是y总说过二分!=单调性)。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 300010;
    
    int n, m;
    int a[N], s[N];
    
    vector<int> alls;
    vector<PII> 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;
    }
    
    vector<int>::iterator unique(vector<int> &a)
    {
        int j = 0;
        for (int i = 0; i < a.size(); i ++ )
            if (!i || a[i] != a[i - 1])
                a[j ++ ] = a[i];
        // a[0] ~ a[j - 1] 所有a中不重复的数
    
        return a.begin() + j;
    }
    
    int main()
    {
        cin >> n >> m;
        for (int i = 0; i < n; i ++ )
        {
            int x, c;
            cin >> x >> c;
            add.push_back({x, c});
    
            alls.push_back(x);
        }
    
        for (int i = 0; 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), alls.end());
    
        // 处理插入
        for (auto item : add)
        {
            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), r = find(item.second);
            cout << s[r] - s[l - 1] << endl;
        }
    
        return 0;
    }
  • 相关阅读:
    单例设计模式
    程序员眼中的中国传统文化王阳明《传习录》10
    程序员眼中的中国传统文化王阳明《传习录》8
    程序员眼中的中国传统文化王阳明《传习录》16
    程序员眼中的中国传统文化王阳明《传习录》11
    程序员眼中的中国传统文化王阳明《传习录》15
    程序员眼中的中国传统文化王阳明《传习录》14
    程序员眼中的中国传统文化王阳明《传习录》9
    程序员眼中的中国传统文化王阳明《传习录》13
    程序员眼中的中国传统文化王阳明《传习录》12
  • 原文地址:https://www.cnblogs.com/zyz010206/p/12348321.html
Copyright © 2011-2022 走看看