题目大意
给定一片蘑菇田,只有从(1,1)至(1000,1000)的整数点能产蘑菇,点(x,y)的蘑菇产量为(x+A)(y+B)
给定直角三角形的两个顶点和斜边的斜率,用(a,b)的形式给出,求该三角形内的蘑菇产量和。
解题思路
因为点最多有1000*1000=100W个,可以先求出他们斜率并排序,找到每个斜率的rank,并将询问按照极角排序,离线将询问的斜率也排序,逆时针每个点加入线段树。询问实际上就是求一个前缀和了。一边处理询问,一边处理这些点。
每次区间更新[p,1000](相当于添加一条权值为(x+A)(y+B)的线段),单点查询该点值。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
using namespace std;
inline int ReadInt()
{
int flag=0;
char ch=getchar();
int data=0;
while (ch<'0'||ch>'9')
{
if (ch=='-') flag=1;
ch=getchar();
}
do
{
data=data*10+ch-'0';
ch=getchar();
}while (ch>='0'&&ch<='9');
return data;
}
int A,B;
struct query
{
int p,a,b,r;
}q[100005];
LL addv[5005];
LL ans[100005];
struct node
{
int a,b;
}sl[1000005],tmp;
int cmp2(node x,node y)
{
return (x.b*y.a<x.a*y.b);
}
int cmp1(query x,query y)
{
return (x.b*y.a<x.a*y.b);
}
int cmp(query x,node y)
{
return (x.b*y.a>=x.a*y.b);
}
void update(int o, int L, int R,int le,int ri,LL v)
{
if (le<=L && ri>=R)
addv[o]+=v;
else {
int M = (L + R)>>1;
if (le<=M) update(o<<1,L,M,le,ri,v);
if (ri>M) update(o<<1|1,M+1,R,le,ri,v);
}
}
LL quer(int p,int x,int L,int R)
{
int M = (L + R)>>1;
LL sum=addv[x];
if (L==R) return sum;
if (p<=M) sum+=quer(p,x<<1,L,M);
if (p>M) sum+=quer(p,x<<1|1,M+1,R);
return sum;
}
int main()
{
int T,m,ca=0,cnt=0;
for (int i=1;i<=1000;i++)
for (int j=1;j<=1000;j++)
{
sl[++cnt].a=i;
sl[cnt].b=j;
}
sort(sl+1,sl+1+cnt,cmp2);
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&A,&B);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
q[i].r=i;
q[i].a=ReadInt();
q[i].b=ReadInt();
q[i].p=ReadInt();
}
sort(q+1,q+1+m,cmp1);
memset(addv,0,sizeof addv);
int pt=0;
for (int i=1;i<=m;i++)
{
while (pt<1000000&&cmp(q[i],sl[pt+1]))
{
pt++;
update(1,1,1000,sl[pt].a,1000,(sl[pt].a+A)*(sl[pt].b+B));
}
ans[q[i].r]=quer(q[i].p,1,1,1000);
}
printf("Case #%d:\n",++ca);
for (int i=1;i<=m;i++)
printf("%I64d\n",ans[i]);
}
return 0;
}