位运算&&离散化&&区间合并

121 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情

位运算:

0)一个整数的负数是原数的补码 (也就是取反加1) 所以 ~x+1 =-x

1)求n的第k位数字 :n >> k & 1

2)lowbit(x) 函数: 作用:返回x的最后一位1代表的值 实现:x&(-x) 也可以写成: x&(~x+1)

例子:输入n个数,求每个数的二进制序列中1的个数

#include<iostream>
using namespace std;
int lowbit(int x)
{
    return x&(-x);//x&(~x+1);
}
int main()
{
    int n = 0;
    cin >> n;
    while(n--)
    {
        int x ;
        cin >> x;
        int res = 0;
        while(x)
        {
            x-=lowbit(x); //每次减去x的最后一位1代表的值,相当于把那一位1去掉
            res++;
        }
        cout << res <<" ";
    }
    return 0;
}

离散化

image-20221030104512089

如何实现去重 -> 使用unique函数

vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());// 去掉重复元素

注意:必须先排序,然后再使用unique函数

image-20221030105142294

区间合并

简单来说:就是把有交集的区间进行合并,端点相交也合并

image-20221030105401859


例子:区间合并:www.acwing.com/problem/con…

image-20221030105521505

第一步:按照区间左端点排序,第二步:维护当前的区间[start,end],假设当前扫描到第i个区间,有下面三种情况:

image-20221030105708532


#include<iostream>
#include<vector>
#include<algorithm>using namespace std;
​
int main()
{
    int n;
    cin >> n;
​
    int start,end;
    vector<pair<int,int>> a;
    for(int i = 0 ; i < n ;++i)
    {
        cin >> start >> end;
        a.push_back({start,end});
    }
    //以左端点排升序
    sort(a.begin(),a.end());  //pair排序优先以第一个成员排序,然后以第二个成员排序
    
    //维护[start,end]区间
    start = a[0].first,end = a[0].second;
    int count = 1;
    for(int i = 1 ; i < n ;++i)
    {
        if(end >= a[i].second) //情况1 (当前扫描的区间在当前维护的区间内)
        {
            continue;
        }
        else if(end >= a[i].first) //情况2 :end <= a[i].second && end >= a[i].first
        {
            end = a[i].second; //两个区间有交集,扩大当前维护的区间的尾
        }
        else                   //情况3:区间已经没有交集,更改维护的区间
        {
            start= a[i].first;
            end = a[i].second;
            ++count;//之前的区间合并成一个
        }
    }
​
    cout << count <<endl;
    return 0;
}

写法2:将情况1和情况2合并, 直接取右端点的max作为答案

#include<iostream>
#include<vector>
#include<algorithm>
 
using namespace std;
 
 
void merge(vector<pair<int,int>>& segs) //将所有存在交集的区间合并
{
    vector<pair<int,int>> res;//存储区间合并之后的结果
    //pair排序优先以第一个成员排序,然后以第二个成员排序
    sort(segs.begin(),segs.end()); 
    //维护当前区间,最初没有遍历任何区间,设置一个边界值:负无穷到正无穷
    //因为范围是-10^9 ~10^9 所以范围取:[-2e9,-2e9]
    int st = -2e9 , ed = -2e9;  
    for(auto& e : segs) //扫描所有的区间
    {
        if(ed < e.first) //case1:没有交集
        {
            if(st != -2e9) 
                res.push_back({st,ed}); //合并的区间放到res中
            //更新维护的区间
            st = e.first;
            ed = e.second;
        }
        else   //情况1,2合并 :有交集
        {
            //当前维护的区间和当前区间有交集 ,把右端点更新为更长的那个
            ed = max(ed , e.second);
        }
    }
    
    if(st != -2e9) //为了防止输入的数组里面是没有任何区间的
        res.push_back({st,ed});//把最后一个维护的区间加到答案里面
    
    segs = res;
}
 
int main()
{
    int n;
    cin >> n;
    
    int l,r;
    vector<pair<int,int>> a;
    for(int i = 0 ; i < n ;++i)
    {
        cin >> l >> r;
        a.push_back({l,r});
    }
    
    merge(a);//区间合并
    
    cout << a.size() <<endl;
    return 0;
}

int的最小值为−2147483648,所以取−2e9比较省事,可以代表int的最小值

还有一些可以代表int最小值的数,例如,-0x3f3f3f3f-,-(1<<30)