题意
m m m 个任务,第 i i i 个任务在时间 [ s i , e i ] [s_i,e_i] [si,ei] 内运行,优先级为 p i p_i pi。时间范围是 [ 1 , n ] [1,n] [1,n]。 n n n 次查询,查询第 x x x 秒的所有任务当中,优先级最小的 k k k 个任务的优先级之和。强制在线。
思路
对时间差分。
假设我们可以维护任何一个时刻建的任何优先级。用 c n t cnt cnt 和 s u m sum sum 记录这个时刻的这个优先级的 “个数变化” 以及 “个数变化乘以优先级”。时间 [ s i , e i ] [s_i,e_i] [si,ei] 内有一个权值为 p i p_i pi 的任务,分别处理时刻 s i s_i si 和时刻 e i + 1 e_i+1 ei+1:
- 时间 s i s_i si 新开始了一个任务,所以时刻 s i s_i si 的 c n t cnt cnt 值 + 1 +1 +1, s u m sum sum 值 + p i +p_i +pi;
- 时间 e i + 1 e_i+1 ei+1 结束了一个任务,所以时刻 e i + 1 e_i+1 ei+1 的 c n t cnt cnt 值 − 1 -1 −1, s u m sum sum 值 − p i -p_i −pi。
当我们想要查询时刻 x x x 的任务状态时,其实就是对于每一个优先级,都从 [ 1 , x ] [1,x] [1,x] 将所有 c n t cnt cnt 和 s u m sum sum 求和。这样我们就可以得到了时刻 x x x 每一个优先级的任务数量,以及任务数量和优先级的乘积。
那么怎样把这个二维信息的维护实现呢?就是利用主席树。每一个时刻开一棵线段树,下标是优先级,权值是 c n t cnt cnt 和 s u m sum sum。所有时刻的这 n n n 棵线段树就构成了一棵主席树,因为后一个时刻总是在前一个时刻的基础上插入若干个点。
代码实现如下。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
#define endl "\n"
/********************** Core code begins **********************/
struct segtrs {
struct Info {
int l = 0, r = 0, cnt = 0, sum = 0;
};
vector<Info> info;
int cnt = 0;
segtrs(int n): info(n * 64) {}
// 新开一条链,在位置 x 处的权值 += k
int insert(int p, int l, int r, int x, int k) {
int rt = ++cnt;
info[rt] = info[p];
info[rt].cnt += k;
info[rt].sum += x * k;
if (l == r) {
return rt;
}
int mid = (l + r) >> 1;
if (x <= mid) {
info[rt].l = insert(info[p].l, l, mid, x, k);
} else {
info[rt].r = insert(info[p].r, mid + 1, r, x, k);
}
return rt;
}
// 查询优先级前 k 小的任务优先级之和
int query(int p, int l, int r, int k) {
k = min(k, info[p].cnt);
if (l == r) {
return k * l;
}
int mid = (l + r) >> 1;
int lp = info[p].l, rp = info[p].r;
if (info[lp].cnt >= k) {
return query(lp, l, mid, k);
} else {
return info[lp].sum + query(rp, mid + 1, r, k - info[lp].cnt);
}
}
};
void SolveTest() {
int m, n;
cin >> m >> n;
struct Task {
int t, p, flg; // 时间点,优先级,开始/结束标志
};
vector<Task> task;
for (int i = 1; i <= m; i++) {
int s, e, p;
cin >> s >> e >> p;
task.push_back({s, p, 1});
task.push_back({e + 1, p, -1});
}
sort(task.begin(), task.end(), [](auto x, auto y) {
return x.t < y.t;
});
const int M = 1e7 + 7; // 优先级的范围
vector<int> root(n + 2);
segtrs tr(n + 2);
int nowt = 0;
for (int i = 0; i < task.size(); i++) {
if (task[i].t == nowt) {
root[nowt] = tr.insert(root[nowt], 1, M, task[i].p, task[i].flg);
} else {
while (nowt < task[i].t - 1) {
nowt++;
root[nowt] = root[nowt - 1];
}
nowt++;
root[nowt] = tr.insert(root[nowt - 1], 1, M, task[i].p, task[i].flg);
}
}
while (nowt < n + 1) {
nowt++;
root[nowt] = root[nowt - 1];
}
int q = n, last = 1;
while (q--) {
int x, a, b, c;
cin >> x >> a >> b >> c;
int k = 1 + (a * last + b) % c;
last = tr.query(root[x], 1, M, k);
cout << last << endl;
}
}
/********************** Core code ends ***********************/
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T;
for (int i = 1; i <= T; i++) {
SolveTest();
}
return 0;
}