练习此题前需先学习差分和离散化的相关知识,尚未学习的同学请学习后再来.
题目链接:http://acm.zzuli.edu.cn/problem.php?id=2694
题目描述
学院一共有 n 位学生,用 1 编号。每天,学院都会派遣辅导员给学生发送若干通知,以保证各项措施、活动消息得到落实。
现在,学院要求辅导员发送一条关于光盘行动的通知。对于通知信息,同学们的反应往往各不相同,辅导员预测出第 i 号学生收到通知后会产生 wi 的愉悦度。此外,辅导员还观察到第 i 号学生会在 [ai,bi]时间段内实时查阅通知消息,能够收到这段时间内的所有通知;而其他时间将无法收到通知(愉悦度为 0)。
辅导员会选择在某一时刻发布一次通知消息,他希望在至少有 k 名同学收到通知的前提下,使得同学们的总体愉悦度最大。同学们的总体愉悦度是所有同学愉悦度的异或和。请聪明的你帮助辅导员计算最大的总体愉悦度。
输入
第一行包含两个整数 n, k (1≤n≤5×105,1≤k≤n),含义见题目描述。
接下来 n 行,每行包含三个整数 ai, bi, wi (1≤ai≤bi≤109, 0≤wi≤109),含义见题目描述。
输出
输出一行一个整数,即最大的总体愉悦度。若不可能有至少 k 名同学收到通知,输出 −1。
样例输入
5 1
1 5 8
3 6 2
7 8 4
8 9 0
10 10 1
样例输出
10
首先看下数据量1<= ai <= bi <= 1e9,但n只有5*1e5,因此很明显需要离散化ai和bi
通过ai,bi,wi可以发现这是对区间的修改操作,很容易想到差分,并且题目中明确说明了求愉悦度的异或合.
因此需要通过差分来维护异或合,最后扫描每一个点来求出最大的异或和即可.
但题目中还有一个条件就是必须大于等于k个人,因此我们可以再开一个数组去维护每个点所能偷税的人数,通过if判断下即可
int maxn = -1;
if(当前点偷税人数 >= k){
maxn = max(maxn,当前点偷税度)
}
此外有一点需要额外注意,这也是本题的难点,就是对于区间a[i]和b[i],我们需要离散化的到底是a[i]和b[i],还是a[i]和b[i] + 1.
因为题目提供的是双闭,如果我们离散化a[i]和b[i]的话会出现重复计算区间和漏算区间的情况.举个例子
3 0
1 5 2
3 10 6
8 12 2
先按b[i]进行离散化
首先查询1(对应lsh后的1),可以发现是2
然后查询3(对应lsh后的2),可以发现是4
然后查询5(对应3),4,这里可以很明显的发现和3重复查询了
因为左右都是闭区间,所以查询右节点,和查询距离该右节点最近的左节点是一样的,即图中区间 [1,3] .而会漏掉 “右节点到右边离该右节点最近的左节点围成的区间” .(即图中区间(5,8))
因此我们需要把原本的左闭右闭修改成左闭右开,让右端点记录 “该右端点到其右边最左断点形成的区间”(在图中就是让5变成6,用6去记录[6,10)的这个区间) ,也就意味这我们需要对a[i]和b[i]+1进行离散化使其变为左闭右开.
最后附上代码吧
#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#include<map>
#include<unordered_map>