Always Cook Mushroom
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 467 Accepted Submission(s): 146
Problem Description
Matt has a company, Always Cook Mushroom (ACM), which produces high-quality mushrooms.
ACM has a large field to grow their mushrooms. The field can be considered as a 1000 * 1000 grid where mushrooms are grown in grid points numbered from (1, 1) to (1000, 1000). Because of humidity and sunshine, the productions in different grid points are not the same. Further, the production in the grid points (x, y) is (x + A)(y + B) where A, B are two constant.
Matt,the owner of ACM has some queries where he wants to know the sum of the productions in a given scope(include the mushroom growing on the boundary). In each query, the scope Matt asks is a right angled triangle whose apexes are (0, 0), (p, 0), (p, q) 1<=p, q<=1000.
As the employee of ACM, can you answer Matt’s queries?
ACM has a large field to grow their mushrooms. The field can be considered as a 1000 * 1000 grid where mushrooms are grown in grid points numbered from (1, 1) to (1000, 1000). Because of humidity and sunshine, the productions in different grid points are not the same. Further, the production in the grid points (x, y) is (x + A)(y + B) where A, B are two constant.
Matt,the owner of ACM has some queries where he wants to know the sum of the productions in a given scope(include the mushroom growing on the boundary). In each query, the scope Matt asks is a right angled triangle whose apexes are (0, 0), (p, 0), (p, q) 1<=p, q<=1000.
As the employee of ACM, can you answer Matt’s queries?
Input
The first line contains one integer T, indicating the number of test cases.
For each test case, the first line contains two integers:A, B(0<=A, B<=1000).
The second line contains one integer M(1<=M<=10^5), denoting the number of queries.
In the following M lines, the i-th line contains three integers a, b, x (1<=a, b<=10^6, 1<=x<=1000), denoting one apex of the given right angled triangle is (x, 0) and the slope of its base is (a, b). It is guaranteed that the gird points in the given right angled triangle are all in valid area, numbered from (1, 1) to (1000, 1000).
For each test case, the first line contains two integers:A, B(0<=A, B<=1000).
The second line contains one integer M(1<=M<=10^5), denoting the number of queries.
In the following M lines, the i-th line contains three integers a, b, x (1<=a, b<=10^6, 1<=x<=1000), denoting one apex of the given right angled triangle is (x, 0) and the slope of its base is (a, b). It is guaranteed that the gird points in the given right angled triangle are all in valid area, numbered from (1, 1) to (1000, 1000).
Output
For each test case, output M + 1 lines.
The first line contains "Case #x:", where x is the case number (starting from 1)
In the following M lines, the i-th line contains one integer, denoting the answer of the i-th query.
The first line contains "Case #x:", where x is the case number (starting from 1)
In the following M lines, the i-th line contains one integer, denoting the answer of the i-th query.
Sample Input
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
Sample Output
Case #1: 1842 1708 86 Case #2: 2901 2688 200
Source
题目大意:
有1000*1000个点,点(x, y)的权值为(x+A)(y+B),对于每次询问,输入(a, b) 和 x,输出以(0, 0)、(x, 0)、(x, x/a*b) 构成的三角行(含边界)包围的点的权值和。
解题思路:
解题的关键在于抓住每个三角形都含有原点(0, 0)这一信息,又可以发现不同的三角行之间有很多重复部分,想办法减少重复计算。
1. 我们可以预处理出1000*1000个点的逆时针极角序集合。
2. 将所有的询问离线操作,按(a, b)逆时针排序,从斜率最小的开始。
3. 对于询问(ai, bi), xi,要求的权值和就是过(0, 0)斜率为(a, b)的这条线以下部分。
4. 线性扫描预处理后的点集,将斜率小于等于(a, b)的点存入树状数组中。处理完后,此次询问的权值和即为[0, xi]的前缀和。
更为形象的说,每次就是将过(0, 0)斜率为(ai, bi)的直线之下,斜率为(ai-1, bi-1)的直线之上的部分压平到x轴上,[0, xi]的前缀和即为权值和。前缀和用树状数组维护。排序是为了重复利用已经插入树状数组的部分,提高效率。
参考代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
const int MAXN = 1010;
const int MAXM = 100010;
int nCase, cCase, A, B, M;
long long bit[MAXN], ans[MAXM];
struct Point {
int x, y;
Point() {}
Point(int _x, int _y) : x(_x), y(_y) {}
bool operator < (const Point &t) const {
return x * t.y - t.x * y > 0;
}
};
vector<Point> point;
struct Query {
int id, a, b, x;
Query() {}
Query(int _id, int _a, int _b, int _x) : id(_id), a(_a), b(_b), x(_x) {}
bool operator < (const Query &t) const {
return a * t.b - t.a * b > 0;
}
};
vector<Query> query;
void init() {
point.clear();
for (int i = 1; i <= 1000; i++) {
for (int j = 1; j <= 1000; j++) {
point.push_back(Point(i, j));
}
}
sort(point.begin(), point.end());
}
void init_case() {
memset(bit, 0, sizeof(bit));
query.clear();
}
void input() {
scanf("%d%d", &A, &B);
scanf("%d", &M);
for (int i = 0; i < M; i++) {
int a, b, x;
scanf("%d%d%d", &a, &b, &x);
query.push_back(Query(i, a, b, x));
}
sort(query.begin(), query.end());
}
long long sum(int i) {
long long s = 0;
while (i > 0) {
s += bit[i];
i -= i & (-i);
}
return s;
}
void add(int i, int x) {
while (i < MAXN) {
bit[i] += x;
i += i & (-i);
}
}
void solve() {
int idx = 0;
for (int i = 0; i < M; i++) {
while (point[idx].x*query[i].b - query[i].a*point[idx].y >= 0) {
add(point[idx].x, (point[idx].x+A) * (point[idx].y+B));
idx++;
}
ans[query[i].id] = sum(query[i].x);
}
}
void output() {
printf("Case #%d:\n", ++cCase);
for (int i = 0; i < M; i++) {
printf("%I64d\n", ans[i]);
}
}
int main() {
init();
scanf("%d", &nCase);
while (nCase--) {
init_case();
input();
solve();
output();
}
return 0;
}