这题的主要的坑点就是他给你的射击目标有重合的部分,如果你向这些重合的部分射击的话要考虑两种情况:
射击目标数量 ≥ 重合数量 : 全加上
射击目标数量 ≤ 重合数量 : 只加距离*射击目标数量
然而这题的内存还是很良心的,总体比较水吧。
主要做法是按照横坐标1~x建立主席树,每棵主席树维护l,r区间的设计目标数量,以及这些数量如果全部被射击获得的分数,这些在建树的时候是很好维护的。
然后对这些线段的处理要用扫描线的思想,就(左端点)建立一个(+1)的入点,(右端点+1)的位置建立一个(-1)的出点,然后从左往右扫一遍即可。
具体过程见代码:
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> #define INF 2*0x3f3f3f3f using namespace std; int n, m, x, p; struct N { int ls, rs, w; long long sum; } tree[6000100]; int roots[200010]; int b[200010], tot, cnt; int build_tree(int l, int r) { int newnode = tot++; tree[newnode].w = 0; tree[newnode].sum = 0; if (l != r) { int mid = (l + r) / 2; tree[newnode].ls = build_tree(l, mid); tree[newnode].rs = build_tree(mid + 1, r); } return newnode; } int updata(int rt, int pos, int val) { int newnode = tot++, tmp = newnode; long long add = b[pos - 1]; tree[newnode].sum = tree[rt].sum + add * val; tree[newnode].w = tree[rt].w + val; int l = 1, r = cnt; while (l < r) { int mid = (l + r) / 2; if (pos <= mid) { tree[newnode].ls = tot++; tree[newnode].rs = tree[rt].rs; newnode = tree[newnode].ls; rt = tree[rt].ls; r = mid; } else { tree[newnode].ls = tree[rt].ls; tree[newnode].rs = tot++; newnode = tree[newnode].rs; rt = tree[rt].rs; l = mid + 1; } tree[newnode].sum = tree[rt].sum + add * val; tree[newnode].w = tree[rt].w + val; } return tmp; } long long query(int rt, int k) { //printf("rt = %d k = %d\n",rt,k); int l = 1, r = cnt; long long ans = 0; while (l < r) { int mid = (l + r) / 2; int tmp = tree[tree[rt].ls].w; if (tmp >= k) { rt = tree[rt].ls; r = mid; } else { k -= tmp; ans += tree[tree[rt].ls].sum; rt = tree[rt].rs; l = mid + 1; } } if (tree[rt].w != 0) ans += tree[rt].sum / tree[rt].w * min(k, tree[rt].w); return ans; } struct P { int x, y, val; P() {} P(int _x, int _y, int _val) : x(_x), y(_y), val(_val) {} bool operator < (const P &rhs) const { return x < rhs.x; } } pois[500010]; void print(int rt, int l = 1, int r = cnt) { printf("l = %d r = %d w = %d sum = %I64d\n", l, r, tree[rt].w, tree[rt].sum); if (l != r) { int mid = (l + r) / 2; print(tree[rt].ls, l, mid); print(tree[rt].rs, mid + 1, r); } } int main() { //freopen("in.in", "r", stdin); //freopen("out.out", "w", stdout); while (scanf("%d %d %d %d", &n, &m, &x, &p) != EOF) { int l1, l2, d; int ps = 0; for (int i = 0; i < n; i++) { scanf("%d %d %d", &l1, &l2, &d); b[i] = d; pois[ps++] = P(l1, d, 1); pois[ps++] = P(l2 + 1, d, -1); } sort(b, b + n); cnt = unique(b, b + n) - b; sort(pois, pois + ps); tot = 0; roots[0] = build_tree(1, cnt); int t = 0; for (int i = 1; i <= x; i++) { roots[i] = roots[i - 1]; while (t < ps && pois[t].x == i) { int tmp = (int)(lower_bound(b, b + cnt, pois[t].y) - b) + 1; roots[i] = updata(roots[i], tmp, pois[t].val); t++; } } /* for (int i = 1; i <= x; i++) { printf("**********************tree %d is : \n", i); print(roots[i]); } */ long long now = 1; int xs, as, bs, cs; for (int i = 0; i < m; i++) { //printf("i = %d\n", i); scanf("%d %d %d %d", &xs, &as, &bs, &cs); long long tmp = query(roots[xs], (now * as + bs) % cs); if (now > p) tmp *= 2; printf("%I64d\n", tmp); now = tmp; } } return 0; }