1000×1000 網格,點 (x,y) 權值 (x+A)(y+B)。
M ≤ 10⁵ 個查詢:每查詢給 (a,b,x),求直角三角形區域和。三角形頂點:(0,0), (x,0), 以及射線 y = (b/a)x 與 x=x 交點 (x, bx/a)。保證所有網格點在 [1,1000] 內。
三角形由 x 軸與射線 θ = atan2(b,a) 夾住。
若將所有網格點按極角 atan2(y,x) 排序,查詢也按 atan2(b,a) 排序。
想像一根射線從 x 軸逆時針掃過:掃過的點即滿足 y/x ≤ b/a 的點。
對於查詢 (a,b,x),需再限制 x ≤ x_q → 樹狀數組維護 x 軸前綴和。
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXG = 1005;
const int MAXQ = 100005;
struct Point {
int x, y;
double ang;
} pts[MAXG * MAXG];
struct Query {
int a, b, x, id;
double ang;
} qs[MAXQ];
ll BIT[MAXG];
ll ans[MAXQ];
int idxMap[MAXQ]; // 原始順序 -> 排序後位置
inline int lowbit(int x) { return x & -x; }
void bitAdd(int x, ll val) {
for (; x <= 1000; x += lowbit(x)) BIT[x] += val;
}
ll bitSum(int x) {
ll res = 0;
for (; x > 0; x -= lowbit(x)) res += BIT[x];
return res;
}
bool cmpPt(const Point& a, const Point& b) { return a.ang < b.ang; }
bool cmpQ(const Query& a, const Query& b) {
if (a.ang != b.ang) return a.ang < b.ang;
return a.x < b.x;
}
int main() {
// 1. 預處理所有網格點極角
int ptCnt = 0;
for (int i = 1; i <= 1000; ++i)
for (int j = 1; j <= 1000; ++j) {
pts[ptCnt].x = i;
pts[ptCnt].y = j;
pts[ptCnt].ang = 1.0 * j / i; // 避免 atan2,單調等價
++ptCnt;
}
sort(pts, pts + ptCnt, cmpPt);
int T;
scanf("%d", &T);
for (int tc = 1; tc <= T; ++tc) {
ll A, B;
int M;
scanf("%lld%lld%d", &A, &B, &M);
for (int i = 0; i < M; ++i) {
scanf("%d%d%d", &qs[i].a, &qs[i].b, &qs[i].x);
qs[i].ang = 1.0 * qs[i].b / qs[i].a;
qs[i].id = i;
}
sort(qs, qs + M, cmpQ);
for (int i = 0; i < M; ++i) idxMap[qs[i].id] = i;
memset(BIT, 0, sizeof(BIT));
int ptr = 0;
for (int i = 0; i < M; ++i) {
while (ptr < ptCnt && pts[ptr].ang <= qs[i].ang) {
ll val = (ll)(pts[ptr].x + A) * (pts[ptr].y + B);
bitAdd(pts[ptr].x, val);
++ptr;
}
ans[i] = bitSum(qs[i].x);
}
printf("Case #%d:\n", tc);
for (int i = 0; i < M; ++i) {
printf("%lld\n", ans[idxMap[i]]);
}
}
return 0;
}