Bootstrap

【算法】离散化与区间合并

离散化

有些情况下,数字的值的绝对大小并不重要,而相对大小很重要。“离散化”是用数字的相对值代替它们的绝对值。

把分布广而稀疏的数据转化为密集分布,从而能够让算法更快速,更省空间地处理。

离散化三步骤:

  • 排序
  • 去重
  • 映射到0,1,2,3这些点,通过二分法进行处理

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

现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。

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

输入格式

第一行包含两个整数 n和 m。

接下来 n 行,每行包含两个整数 x 和 c。

再接下来 m 行,每行包含两个整数 l 和 r。

输出格式

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

数据范围

− 1 0 9 ≤ x ≤ 1 0 9 −10^9≤x≤10^9 109x109,
1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^5 1n,m105,
− 1 0 9 ≤ l ≤ r ≤ 1 0 9 −10^9≤l≤r≤10^9 109lr109,
− 10000 ≤ c ≤ 10000 −10000≤c≤10000 10000c10000

输入样例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例:

8
0
5
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
typedef pair<int,int>PII;
vector<int>alls;
vector<PII>add,query;
int s[N],a[N];
int find(int x)
{
    int l=0,r=alls.size()-1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(alls[mid]<=x)l=mid+1;
        else r=mid-1;
    }
    return r+1;
}
signed main()
{
    int n,x,c,m,l,r;cin>>n;cin>>m;
    while(n--)
    {
        cin>>x>>c;
        add.push_back({x,c});
        alls.push_back(x);
    }
    
    while(m--)
    {
        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)//用auto遍历时是遍历数组内的所有元素,如果不是遍历所有,就不用这种
    {
        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;
}

区间合并

给定 n 个区间 [ l i , r i l_i,r_i li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6]。

输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 l 和 r。

输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围
1 ≤ n ≤ 100000, − 1 0 9 ≤ l i ≤ r i ≤ 1 0 9 −10^9 ≤ l_i ≤ r_i ≤ 10^9 109liri109

输入样例:

5
1 2
2 4
5 6
7 8
7 9

输出样例:

3

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>PII;
const int N=100010;
int n;
vector<PII>segs;
void merge(vector<PII>&segs)
{
    vector<PII>res;
    sort(segs.begin(),segs.end());//要先按区间左端点排序
    int st=-2e9,ed=-2e9;
    for(auto seg:segs)
    {
        
        if(ed<seg.first)//第一种情况是所维护的区间的右端点与遍历的
        {
            if(st!=-2e9)res.push_back({st,ed});
            st=seg.first,ed=seg.second;
        }else ed=max(ed,seg.second);
        
    }
    if(st!=-2e9)res.push_back({st,ed});//把最后一个点加进去
    segs=res;//将res赋给segs
}
int main()
{
    cin>>n;int l,r;
    while(n--)
    {
       cin>>l>>r;
       segs.push_back({l,r});
    }
    merge(segs);
    cout<<segs.size();
    return 0;
}
;