洛谷题单指南-线段树的进阶用法-P3168 [CQOI2015] 任务查询系统
原题链接:https://www.luogu.com.cn/problem/P3168
题意解读:一个任务管理系统,能够查询在某个时间点运行的任务中优先级最小的 k个任务的优先级之和。
解题思路:
由于总时间n不超过100000,考虑针对所有时刻建立可持久化线段树,根节点为root[i]的线段树维护时刻i的任务情况,节点区间表示优先级,节点cnt表示某个优先级的任务数量,节点sum表示某个优先级的任务的优先级之和。
对于一个任务三元组(s, e, p),可以分解来看,对s时刻的线段树应该针对值p的数量加1,而e + 1时刻的线段树应该针对值p的数量减1。
而每一个时刻的线段树应该是基于前一个时刻的线段树复制过来的,这样就能保证每个时刻正在运行的任务是正确的!
查询操作只需要查询时刻x的一棵线段树,要查询前k小的优先级之和,需要注意一点:如果有相同优先级的任务超过k个,那么递归时会到叶子节点,此时返回的优先级之和应该是该叶子节点的优先级 * k。
其余代码都是可持久化线段树的正常操作。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005, P = 1e7;
typedef long long LL;
struct Task
{
int t; // 任务时间
bool start; // 是否是任务开始时间 true:开始 false:结束
LL p; // 任务优先级
};
vector<Task> tk[N]; // 每个时刻所有的任务,开始、结束拆分处理
struct Node
{
int L, R;
int cnt; // 任务数量
LL sum; // 优先级和
} tr[N * 50]; // 线段树节点
int root[N], idx; // 线段树根节点,节点编号
int m, n;
//通过复制节点的方式更新线段树,将根为pre的线段树中值v的数量加num
int update(int pre, int l, int r, int v, int num)
{
int u = ++idx;
tr[u] = tr[pre]; // 复制节点
tr[u].cnt += num;
tr[u].sum += num * v;
if (l == r) return u;
int mid = (l + r) >> 1;
if (v <= mid) tr[u].L = update(tr[u].L, l, mid, v, num);
else tr[u].R = update(tr[u].R, mid + 1, r, v, num);
return u;
}
//在根为u的线段树中查询前k小任务的优先级和
LL query(int u, int l, int r, int k)
{
if (tr[u].cnt <= k) return tr[u].sum; // u节点所在树所有任务数量小于等于k的全部选
if(l == r) return l * k; // 考虑到会有相同优先级任务数量超过k个,在递归到叶子节点时,则只取k个该叶子节点的值
int mid = (l + r) >> 1;
if (tr[tr[u].L].cnt >= k) return query(tr[u].L, l, mid, k);
else return tr[tr[u].L].sum + query(tr[u].R, mid + 1, r, k - tr[tr[u].L].cnt);
}
int main() {
cin >> m >> n;
int s, e, p;
for (int i = 1; i <= m; i++)
{
cin >> s >> e >> p;
tk[s].push_back({s, true, p});
tk[e + 1].push_back({e + 1, false, p});
}
for (int i = 1; i <= n; i++)
{
root[i] = root[i - 1];
for (auto task : tk[i])
{
if (task.start) root[i] = update(root[i], 1, P, task.p, 1);
else root[i] = update(root[i], 1, P, task.p, -1);
}
}
LL pre = 1;
int x, a, b, c;
for (int i = 1; i <= n; i++)
{
cin >> x >> a >> b >> c;
int k = 1 + (a * pre + b) % c;
pre = query(root[x], 1, P, k);
cout << pre << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?