【LittleXi】规划兼职工作
心路历程:
早上起来打开题目,一点思路没有
摆烂点开《戴森球》就到中午了,退出游戏,一眼线段树,直接秒了
总结:打游戏,也可以提高思维能力
解题思路
线段树+离散化+dp
离散化:因为时间太长(1e9)所以我们应该对时间排序,用顺序1、2、3来模拟时间次序
dp:将线段按第一个节点排序,对于到达每个节点的最大利润,可以从前面所有节点中的最大利润转移过来即nowprofit=前面所有节点中的最大利润+profit[now]
线段树:在寻找前面的最大利润是,我们可以想到用线段树寻找区间最大值
时间复杂度:O(nlogn)
代码
#define lc k<<1
#define rc k<<1|1
const int maxn = 500010;
const int inf = 0x3f3f3f3f;
int n, a[maxn];
struct node
{
int l, r, mx;
};
node tree[maxn * 4];
void build(int k, int l, int r)//创建叶子节点,k表示存储下标,l,r表示更新区间
{
tree[k].l = l;
tree[k].r = r;
if (l == r)
{
tree[k].mx = a[l];
return;
}
int mid = (l + r) / 2;
build(lc, l, mid);
build(rc, mid + 1, r);
tree[k].mx = max(tree[lc].mx, tree[rc].mx);
}
void update(int k, int i, int v)//点更新,将a[i]修改为v
{
if (tree[k].l == tree[k].r && tree[k].l == i)
{
tree[k].mx = v;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
if (i <= mid)
update(lc, i, v);
else
update(rc, i, v);
tree[k].mx = max(tree[lc].mx, tree[rc].mx);
}
int query(int k, int l, int r)//区间覆盖查询,求区间[l,r]的最大值
{
if (tree[k].l >= l && tree[k].r <= r)
return tree[k].mx;
int mid = (tree[k].l + tree[k].r) / 2;
int ma = -inf;
if (l <= mid)
ma = max(ma, query(lc, l, r));
if (r > mid)
ma = max(ma, query(rc, l, r));
return ma;
}
class Solution {
public:
int jobScheduling(vector<int>& st, vector<int>& en, vector<int>& pr) {
int n = st.size();
vector<vector<int>> vec(n);
set<int> lisan;
for (int i = 0; i < n; i++)
{
lisan.insert(st[i]);
lisan.insert(en[i]);
}
int p = 1;
unordered_map<int, int> m;
for (auto& val:lisan)
{
m[val] = p++;
}
for (int i = 0; i < n; i++)
{
vec[i].push_back(m[st[i]]);
vec[i].push_back(m[en[i]]);
vec[i].push_back(pr[i]);
}
sort(vec.begin(), vec.end(), [&](vector<int>& v1,
vector<int>& v2) {return v1[0] < v2[0]; });
memset(a, 0, sizeof(a));
build(1, 0, 500005);
for (int i = 0; i < n; i++)
{
int be = vec[i][0];
int en = vec[i][1];
int money = vec[i][2];
int temp = query(1, 1, be);
a[en] = max(a[en],temp + money);
update(1, en, a[en]);
}
int re = *max_element(a, a + 500000);
return re;
}
};