一些平行于x轴的线段作为射击目标,每次在x轴上选一个点向y轴方向射击,可以射中最近的k个目标,得分是射中目标的高度和,求这个得分。
对高度建立函数式线段树,按顺序对x轴坐标建树,维护区间和和区间个数,每次射击询问该线段树即可。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
#define N 5522222
#define LL long long
#define mod 1000000007ll
#define inf 0XFFFFFFF
#define pii pair<int, int>
#define mp make_pair
#define eps 1e-3
#define euC 0.57721566490153286060651209
struct Seg {
int cnt; LL sum;
int l, r;
Seg *ch[2];
} pool[N];
Seg *tot;
Seg* newNode() {
tot->cnt = tot->sum = 0;
tot->l = tot->r = 0;
tot->ch[0] = tot->ch[1] = NULL;
return tot++;
}
Seg *root[N];
Seg* buildtree(int l, int r) {
Seg *ret = newNode();
ret->l = l;
ret->r = r;
if (l == r)
return ret;
int mid = (l + r) / 2;
ret->ch[0] = buildtree(l, mid);
ret->ch[1] = buildtree(mid + 1, r);
return ret;
}
LL H[N];
Seg* update(int w, int x, Seg *now) {
Seg *ret = newNode();
*ret = *now;
if (ret->l == ret->r) {
ret->cnt += x;
ret->sum += H[ret->l] * x;
return ret;
}
int mid = (ret->l + ret->r) / 2;
if (w <= mid)
ret->ch[0] = update(w, x, ret->ch[0]);
else
ret->ch[1] = update(w, x, ret->ch[1]);
ret->cnt = ret->ch[0]->cnt + ret->ch[1]->cnt;
ret->sum = ret->ch[0]->sum + ret->ch[1]->sum;
return ret;
}
pair<int, LL> get(int l, int r, Seg *now) {
pair<int, LL> ret;
if (l <= now->l && now->r <= r)
return make_pair(now->cnt, now->sum);
int mid = (now->l + now->r) / 2;
if (l <= mid) {
pair<int, LL> tmp = get(l, r, now->ch[0]);
ret.first += tmp.first;
ret.second += tmp.second;
}
if (r > mid) {
pair<int, LL> tmp = get(l, r, now->ch[1]);
ret.first += tmp.first;
ret.second +=tmp.second;
}
return ret;
}
int n, m, X;
LL P;
int x[N];
inline int read() {
int ret;
scanf("%d", &ret);
return ret;
}
int Main() {
while (scanf("%d", &n) != EOF) {
tot = pool;
multiset<pii> pos, neg;
set<int> st;
scanf("%d%d", &m, &X);
P = read();
for (int i = 0; i < n; i++) {
int l, r, d;
scanf("%d%d%d", &l, &r, &d);
st.insert(d);
pos.insert(mp(l, d));
neg.insert(mp(r + 1, d));
}
int num = 0;
H[++num] = 0;
for (set<int>::iterator po = st.begin(); po != st.end(); po++) {
H[++num] = *po;
}
sort(H + 1, H + num + 1);
int all = 0;
root[all++] = buildtree(1, num);
while (pos.size() || neg.size()) {
if (pos.size() && (neg.size() == 0 || pos.begin()->first <= neg.begin()->first)) {
x[all] = pos.begin()->first;
int rank = lower_bound(H + 1, H + num + 1, pos.begin()->second) - H;
root[all] = update(rank, 1, root[all-1]);
all++;
pos.erase(pos.begin());
} else {
x[all] = neg.begin()->first;
int rank = lower_bound(H + 1, H + num + 1, neg.begin()->second) - H;
root[all] = update(rank, -1, root[all-1]);
all++;
neg.erase(neg.begin());
}
}
LL pre = 1;
for (int _m = 0; _m < m; _m++) {
int xx;
LL aa, bb, cc;
scanf("%d", &xx);
aa = read(); bb = read(); cc = read();
LL kk = (aa * pre + bb) % cc;
xx = upper_bound(x, x + all, xx) - x - 1;
int l = 1, r = num;
while (l < r) {
int mid = (l + r) / 2;
pair<int, LL> tmp = get(1, mid, root[xx]);
if (tmp.first < kk) l = mid + 1;
else r = mid;
}
pre = (pre > P) ? 2 : 1;
pair<int, LL> tmp = get(1, l, root[xx]);
LL bei = 0;
if (tmp.first > kk)
bei = tmp.first - kk;
pre *= tmp.second - H[l] * bei;
printf("%I64d\n", pre);
}
}
return 0;
}
int main() {
return Main();
}
本文介绍了一种使用函数式线段树解决特定射击问题的方法。问题涉及一系列平行于x轴的线段,通过在x轴上选择点进行射击,并计算击中目标的高度总和。文中详细解释了如何构建和更新线段树,以及如何查询最优得分。
284

被折叠的 条评论
为什么被折叠?



