标签:
题意是这样,给定一个1000x1000的点阵,m组询问,每次询问一个由(0,0)、(x,0)点一以及从原点出发的方向向量(a,b)构成的直角三角形包围的点的权值和。
点的权值是(x+A)(y+B),其中A,B是给定的常数
做法也很显然,将查询离线下来按照方向向量排序,之后的操作就相当于用一根端点在原点的线从x轴开始往y轴扫,不断地把扫到的点的权值加入到树状数组中。每次扫到某个查询的方向向量时,用这个三角形的底边求前缀和,记录下来就好了。
权值会爆int,注意下就好了
#include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<climits> #include<list> #include<iomanip> #include<stack> #include<set> using namespace std; typedef long long ll; ll bit[1010]; void update(int pos,ll val) { for(int i=pos;i<=1000;i+=i&-i) bit[i]+=val; } ll psum(int pos) { ll ans=0; for(int i=pos;i>0;i-=i&-i) ans+=bit[i]; return ans; } struct Point { int x,y; bool operator <(Point one)const { return y*one.x<=one.y*x; } }point[1000010]; struct Qu { int x,y,len,no; bool operator <(Qu one)const { return ll(y*one.x)<ll(one.y*x); } }qu[1000010]; ll ans[1000010]; int main() { int n=0; for(int i=1;i<=1000;i++) for(int j=1;j<=1000;j++) { point[n].x=i; point[n++].y=j; } sort(point,point+n); int T; scanf("%d",&T); for(int cs=1;cs<=T;cs++) { int a,b,m; scanf("%d%d%d",&a,&b,&m); for(int i=0;i<m;i++) { scanf("%d%d%d",&qu[i].x,&qu[i].y,&qu[i].len); qu[i].no=i; } sort(qu,qu+m); memset(bit,0,sizeof(bit)); for(int i=0,j=0;i<m;i++) { Point t; t.x=qu[i].x; t.y=qu[i].y; while(j<n&&point[j]<t) { update(point[j].x,ll(point[j].x+a)*(point[j].y+b)); j++; } ans[qu[i].no]=psum(qu[i].len); } printf("Case #%d:\n",cs); for(int i=0;i<m;i++) cout<<ans[i]<<endl; } }
Time
Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 518 Accepted Submission(s): 157
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
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/stl112514/article/details/46952839