\(n\)个武器\(m\)个盾牌,无论是武器还是盾牌都有相应的攻击值(防御值)和价格,同时还有\(p\)只怪物,每只怪物都有防御值、攻击值、和干掉它能有多少钱。你只能选择一件武器和一件盾牌去,问最终通过打怪获得最多的钱是多少(减去买武器和盾牌的花费后)?
最朴素的想法是\(O(nmp)\),显然不行。那怎么入手呢?只考虑一维的话,对武器和怪物分别排序后,二分加算后缀就能解决。现在多了一维:盾牌和怪兽的攻击,有点难办了。对于每一件武器,假如它能杀死(仅仅只是武器的攻击值大于怪兽的防御值)的怪兽集合是\(S\),那么怎么求集合\(S\)中能获得的最大收益呢?建一颗线段树,用来维护集合\(S\)的最大收益,每加入一个怪兽,假如它的攻击值为\(x\),那么就更新大于\(x\)的那部分的最大值。举例来说:令\(a[i] :=\) 防御值为 \(i\) 的盾牌在集合S中能帮助您取得的最大收益,加入一个攻击值为\(x\)的怪兽,就更新:\(a[x + 1] += coins, a[x + 2] += coins, ···\),然后取它们的最大值\(max(a)\)就是集合\(S\)的最大收益。
当盾牌的防御值相同时,肯定选价格较低的那个盾牌,也就是在建树的函数中:
ma[root] = max(ma[root], -b.price)
。
struct monster {
int x, y, z;
bool operator < (const monster o) const {
return x < o.x;
}
};
int n, m, p, cnt;
long long ma[1000005 * 4], laz[1000005 * 4];
void Build_Tree(int l, int r, int root, int pos, int x) {
if ((l == r) && (l == pos)) {
ma[root] = max(ma[root], (long long)-x); // 坑点1
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) Build_Tree(l, mid, root << 1, pos, x);
else Build_Tree(mid + 1, r, (root << 1) + 1, pos, x);
ma[root] = max(ma[root << 1], ma[(root << 1) + 1]);
}
void Push_down(int root) {
laz[root << 1] += laz[root];
laz[(root << 1) + 1] += laz[root];
ma[(root << 1)] += laz[root];
ma[(root << 1) + 1] += laz[root];
laz[root] = 0;
}
void Update_Tree(int L, int R, int l, int r, int root, int coins) {
if (L > R) return; // 坑点2
if (L <= l && r <= R) {
ma[root] += coins;
laz[root] += coins;
return;
}
if (laz[root]) Push_down(root);
int mid = (l + r) >> 1;
if (L <= mid) Update_Tree(L, R, l, mid, root << 1, coins);
if (R > mid) Update_Tree(L, R, mid + 1, r, (root << 1) + 1, coins);
ma[root] = max(ma[root << 1], ma[(root << 1) + 1]);
}
int main()
{
scanf("%d %d %d", &n, &m, &p);
vector<pair<int, int> > a(n), b(m);
vector<struct monster > c(p);
int length = 0;
myfor(i, 0, n) scanf("%d %d", &a[i].first, &a[i].second);
myfor(i, 0, m) scanf("%d %d", &b[i].first, &b[i].second), length = max(length, b[i].first);
myfor(i, 0, p) scanf("%d %d %d", &c[i].x, &c[i].y, &c[i].z), length = max(length, c[i].y);
sort(a.begin(), a.end());
sort(c.begin(), c.end());
myfor(i, 0, length * 4) ma[i] = -INF;
myfor(i, 0, m) Build_Tree(1, length, 1, b[i].first, b[i].second);
int index = 0;
long long ans = -INF;
myfor(i, 0, n) {
while(index < p && c[index].x < a[i].first) {
Update_Tree(c[index].y + 1, length, 1, length, 1, c[index].z); // length = max(c.y), 所以可能会出现:c[index].y + 1 > length
index++;
}
ans = max(ans, ma[1] - a[i].second);
}
cout << ans << endl;
return 0;
}
原文:https://www.cnblogs.com/zgglj-com/p/12676739.html