给定若干个任务 (si,ei,pi) (s_i, e_i, p_i) ,表示该任务从第 si s_i 秒运行到第 ei e_i 秒,它的价值为 pi p_i ,每次询问给定一个 x x 并由你计算一个 k k ,查询第 x x 秒时价值最小的 k k 个任务的价值之和,如果第 x x 秒时运行的任务不足 k k 个,则输出此时所有任务的价值和。

题解

这里用一种差分的思想来建主席树。

考虑当我们接受到一个任务时,它会从第 si s_i 秒存在到第 ei e_i 秒,而且查询是查询第 x x 秒存在的的所有任务,所以我们对于时间建主席树,对于一个任务 i i ,我们在建第 si s_i 棵线段树时把它插入主席树,在建 ei+1 e_i + 1 棵线段树时把它删掉,这样我们可以保证第 i i 棵线段树中存储的任务是所有在第 i i 秒中运行的任务,剩下的就是主席树上二分查询了。。

注意,相同优先级的任务可能有多个。

顺便吐个槽,感觉这种写法叫做可持久化权值线段树更好。。

代码

奇怪的类名实例名什么的不要在意啦 qwq

#include <cassert>
#include <cstdio>
#include <climits>
#include <algorithm>
#include <vector>
const int MAXN = 100000;
const int MAXM = 100000;
struct Mission {
int val;
bool isDelete;
Mission() {}
Mission(int val, bool isDelete) : val(val), isDelete(isDelete) {}
};
std::vector<Mission> a[MAXM + 50];
struct PresentTreeByGoldYeInInternationalOlympidInInformaticsHellc {
struct Node {
int l, r;
Node *lc, *rc;
int size, sum;
Node() {}
Node(int l, int r, Node *lc, Node *rc) : l(l), r(r), lc(lc), rc(rc), size(lc->size + rc->size), sum(lc->sum + rc->sum) {}
Node(int l, int r, Node *lc, Node *rc, int size, int sum) : l(l), r(r), lc(lc), rc(rc), size(size), sum(sum) {}
} *roots[MAXN + 50], *null, _pool[MAXN * 200], *_curr;
int l, r;
PresentTreeByGoldYeInInternationalOlympidInInformaticsHellc() {
null = new Node(-1, -1, NULL, NULL, 0, 0);
null->lc = null, null->rc = null;
}
Node *insert(Node *v, int l, int r, int x, bool isDelete) {
if (!isDelete) {
if (x < l || x > r) return v;
else if (l == r) return new (_curr++) Node(l, r, null, null, v->size + 1, v->sum + x);
else {
int mid = l + (r - l) / 2;
return new (_curr++) Node(l, r, insert(v->lc, l, mid, x, isDelete), insert(v->rc, mid + 1, r, x, isDelete));
}
} else {
if (x < l || x > r) return v;
else if (l == r) return new (_curr++) Node(l, r, null, null, v->size - 1, v->sum - x);
else {
int mid = l + (r - l) / 2;
return new (_curr++) Node(l, r, insert(v->lc, l, mid, x, isDelete), insert(v->rc, mid + 1, r, x, isDelete));
}
}
}
/*
void update(Node *v, int x, bool isDelete) {
if (!isDelete) {
v->size++, v->sum += x;
if (v->l == v->r) return;
else {
int mid = v->l + (v->r - v->l) / 2;
if (x <= mid) update(v->lc, x, isDelete);
else update(v->rc, x, isDelete);
}
} else {
v->size--, v->sum -= x;
if (v->l == v->r) return;
else {
int mid = v->l + (v->r - v->l) / 2;
if (x <= mid) update(v->lc, x, isDelete);
else update(v->rc, x, isDelete);
}
}
}
*/
void build(std::vector<Mission> *a, int n, int l, int r) {
_curr = _pool;
roots[0] = null;
for (int i = 1; i <= n; i++) {
std::vector<Mission>::iterator it = a[i].begin();
if (it == a[i].end()) { roots[i] = roots[i - 1]; continue; }
else {
roots[i] = insert(roots[i - 1], l, r, it->val, it->isDelete);
it++;
for (; it != a[i].end(); it++) {
assert(it != a[i].end());
roots[i] = insert(roots[i], l, r, it->val, it->isDelete);
}
}
}
this->l = l, this->r = r;
}
long long query(int qr, int k) {
long long ans = 0, lsize;
Node *v = roots[qr];
if (k >= v->size) return v->sum;
lsize = v->lc->size;
while (v->l != v->r) {
if (k <= lsize) {
v = v->lc;
lsize = v->lc->size;
} else {
k -= lsize;
ans += v->lc->sum;
v = v->rc;
lsize = v->lc->size;
}
}
if (k) ans += v->l * k;
return ans;
}
} presentTreeByGoldYeInInternationalOlympidInInformaticsHellc;
int main() {
int m, n;
scanf("%d %d", &m, &n);
int max = INT_MIN, min = INT_MAX;
for (int i = 1; i <= m; i++) {
int s, t, val;
scanf("%d %d %d", &s, &t, &val);
max = std::max(max, val);
min = std::min(min, val);
a[s].push_back(Mission(val, false));
a[t + 1].push_back(Mission(val, true));
}
presentTreeByGoldYeInInternationalOlympidInInformaticsHellc.build(a, n, min, max);
long long pre = 1;
for (int i = 1; i <= n; i++) {
int x, k;
long long a, b, c;
scanf("%d %lld %lld %lld", &x, &a, &b, &c);
k = 1 + (a * pre + b) % c;
pre = presentTreeByGoldYeInInternationalOlympidInInformaticsHellc.query(x, k);
printf("%lld\n", pre);
}
return 0;
}