2 0 0 3 3 5 8 2 4 7 1 2 3 1 2 3 3 5 8 2 4 7 1 2 3
Case #1: 1842 1708 86 Case #2: 2901 2688 200
思路: 预处理出这1e6个点的极角关系序,离线,将询问也按(a,b)的极角排序。然后只需想象一根表针在逆时针的扫,把扫过的点的权值加到树状数组中,对于每一个询问也仅仅是一个前缀和。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> typedef long long ll; using namespace std; const int maxn = 1005; const int inf = 1e5+5; struct Point { ll a, b; double s; } p[maxn*maxn]; struct Query { ll a, b, x, id; double s; } q[maxn*maxn]; ll bit[maxn]; ll ans[inf], Index[inf]; int cnt; void scan(ll &x) { char c; while ((c = getchar()) && (c < '0' || c > '9')) ; x = c - '0'; while ((c = getchar()) && (c >= '0' && c <= '9')) x = x * 10 + c - '0'; } void out(ll x) { if (x > 9) out(x/10); putchar(x%10+'0'); } inline int lowbit(int x) { return x & -x; } inline void add(int x, int val) { while (x <= 1000) { bit[x] += val; x += lowbit(x); } } inline ll sum(int x) { ll tmp = 0; while (x > 0) { tmp += bit[x]; x -= lowbit(x); } return tmp; } bool cmp1(Point x, Point y) { return x.s < y.s; } bool cmp2(Query x, Query y) { if (x.s == y.s) return x.x < y.x; return x.s < y.s; } void init() { for (int i = 1; i <= 1000; i++) for (int j = 1; j <= 1000; j++) { p[cnt].a = i; p[cnt].b = j; p[cnt++].s = 1.0 * j / i; } sort(p, p+cnt, cmp1); } int main() { cnt = 0; ll A, B, m; init(); int t, cas = 1; scanf("%d", &t); while (t--) { memset(bit, 0, sizeof(bit)); scan(A), scan(B), scan(m); for (int i = 0; i < m; i++) { scan(q[i].a), scan(q[i].b), scan(q[i].x); q[i].s = 1.0 * q[i].b / q[i].a; q[i].id = i; } sort(q, q + m, cmp2); for (int i = 0; i < m; i++) { Index[q[i].id] = i; } cnt = 0; printf("Case #%d:\n", cas++); for (int i = 0; i < m; i++) { while (p[cnt].s <= q[i].s) { add(p[cnt].a, (p[cnt].a+A) * (p[cnt].b + B)); cnt++; } ans[i] = sum(q[i].x); } for (int i = 0; i < m; i++) { out(ans[Index[i]]); printf("\n"); } } return 0; }