1.题目描述:点击打开链接
2.解题思路:本题利用极角排序+BIT解决。不过这种思路实在是不容易想到。首选把(1,1)~(1000,1000)都存入数组,并按照他们的斜率排序,然后对输入的m条询问也当做点来看待,当然,这些“点”不能和前面预处理的那些点混淆,这些点表示的是询问点,需要保存询问点的信息有:直角顶点(x,0),斜率(b/a),答案(ans),询问的id(i)。对这些询问也按照斜率由小到大排序,这样,在当前点的斜率值小于询问点的斜率时,执行add(xi,val)操作,最后的答案就是query(xi)。其实这里是一个非常微妙而精彩的做法。虽然题目中说的是第(i,j)处的val是(i+A)*(j+B),但是由于最后是一个求和的过程,因此可以等效理解成所有x值相同的val都加到x轴对应的点上,(这和《概率论》中的二维随机变量概率分布和它的边缘分布非常类似),然后,对xi求前缀和就是整个三角形的val值之和。找下一个点的答案时,直接在现有的x轴基础上继续操作即可。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
const int N=1000005;
int A,B,m;
struct Point
{
int x,y;
ll ans;
double p;
}s[N],sc[N];
bool cmpp(Point a,Point b){return a.p<b.p;}
bool cmpid(Point a,Point b){return a.y<b.y;}
ll bit[1005]; //x轴的最大范围只有1000
int lowbit(int x){return x&-x;}
void add(int x,ll v)
{
while(x<=1000)
{
bit[x]+=v;
x+=lowbit(x);
}
}
ll query(int x)
{
ll ans=0;
while(x>0)
{
ans+=bit[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
int T;
int cnt=0;
scanf("%d",&T);
for(int i=1;i<=1000;i++)
for(int j=1;j<=1000;j++)
s[cnt++]=Point{i,j,0,1.0*j/i};
sort(s,s+cnt,cmpp);
for(int kase=1;kase<=T;kase++)
{
scanf("%d%d",&A,&B);
scanf("%d",&m);
int a,b,x;
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
scanf("%d",&x);
sc[i]=Point{x,i,0,1.0*b/a};
}
sort(sc,sc+m,cmpp);
me(bit);
int now=0;
for(int i=0;i<m;i++)
{
while(s[now].p<=sc[i].p)//只要斜率小于当前询问点的斜率,就继续执行add操作
{
add(s[now].x,(ll)(s[now].x+A)*(s[now].y+B));
now++;
}
sc[i].ans=query(sc[i].x);
}
sort(sc,sc+m,cmpid);//所有询问点的答案都得到后,还按照它们的id排序
printf("Case #%d:\n",kase);
for(int i=0;i<m;i++)
printf("%I64d\n",sc[i].ans);
}
}