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

位运算

看n的二进制表示的数字的第k位是几的操作

 二进制位数是从0开始的,右移0位表示不动

比如10的二进制表示是1010,右移3位就是1

x中最后一位1的位置

 x&(~x+1),~x即x取反,1变0,0变1,然后加1,&x

补码等于源码取反码加一

二进制中1的个数

#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;


const int N = 100010;
int a[N], b[N];

int lowbit(int x)
{
	return x & (-x);
}


int main()
{
	int n;
	cin >> n;
	int sum;
	while (n--)
	{
		int e;
		cin >> e;
	    sum = 0;
		while (e)
		{
			e -= lowbit(e);
			sum++;
		}
		cout << sum << ' ';
	}
	return 0;
}

离散化

排序,去重,快速映射

sort是排序,unique是去重,将重复元素排在最后面,然后返回有效数组的尾指针,最后erase函数删除这些重复的数 

二分求出离散化的值

for(auto i: v)遍历容器元素


1. auto
2. auto&
3. const auto&
4. const auto
C++11 新增了一种循环:基于范围(range-based)的 for 循环。这简化了一种常见的循环任务:对数组(或容器类,如 vector 和 array)的每个元素执行相同的操作,如下例所示:

double prices[5] = {4.99, 10.99, 6.87, 6.47, 8.88};
for (double x : prices)
    std::cout << x << std::endl;
1
2
3
其中,x xx 最初表示数组 prices 的第一个元素。显示第一个元素后,不断执行循环,而 x xx 依次表示数组的其他元素。因此,该循环可以用来显示数组中的每个值。

要修改数组的元素,需要使用不同的循环变量语法:

for (double &x : prices)
    x = x * 0.80; //20% off sale
1
2
符号 & 表明 x xx 是一个引用变量,能让接下来的代码能够修改数组的内容,而第一种语法不能。

还可结合使用基于范围的 for 循环和初始化列表:

for (int x : {3, 5, 2, 8, 6})
    cout << x << " ";
cout << '\n';
1
2
3
这种方式可以引申至 C++11 的另一种新特性 auto,使用 auto 遍历容器的方式,有以下几种:

1. auto
auto 即 for(auto x: range) 这样会拷贝一份 range 元素,而不会改变 range 中元素;

2. auto&
当需要修改range中元素,用 for(auto& x: range);

3. const auto&
当只想读取 range 中元素时,使用 const auto&,如:for(const auto&x:range),它不会进行拷贝,也不会修改range;

4. const auto
当需要拷贝元素,但不可修改拷贝出来的值时,使用 for(const auto x:range),避免拷贝开销。
 

区间和

#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;

const int N = 300010;

typedef pair<int, int> PII;

vector<int> alls;
vector<PII>add, query;

int a[N], s[N];

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;
	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.begin(), alls.end()), 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;
}

find()中返回r+1是为了让a数组从1开始,这样前缀和比较方便

前缀和处理的特殊之处,从i = 1开始,结束条件为i<=alls.size() 

区间合并

步骤:  

 

#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;

const int N = 300010;

typedef pair<int, int> PII;

vector<PII>segs;

int a[N], s[N];

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;
}

int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int l, r;
		cin >> l >> r;
		segs.push_back({ l,r });
	}

	merge(segs);
	cout << segs.size();

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值