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
题目大意
给定一片蘑菇田,只有从(1,1)至(1000,1000)的整数点能产蘑菇,点(x,y)的蘑菇产量为(x+A)(y+B)
给定直角三角形的两个顶点和斜边的斜率,用(a,b)的形式给出,求该三角形内的蘑菇产量和。
解题思路
因为点最多有1000*1000=100W个,可以先求出他们斜率并排序,找到每个斜率的rank,并将询问按照极角排序,离线将询问的斜率也排序,逆时针每个点加入线段树。询问实际上就是求一个前缀和了。一边处理询问,一边处理这些点。
每次区间更新[p,1000](相当于添加一条权值为(x+A)(y+B)的线段),单点查询该点值。
线段树的习惯不是很好……
第一版的代码输入优化4950ms险过(按照斜率离散化)
#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[2500010]; 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 cmp(query x,query y) { return (x.p<y.p); } int cmp1(query x,query y) { return (x.r<y.r); } int t[1005][1005]; int v; void update(int o, int L, int R,int le,int ri) { if (le<=L && ri>=R) addv[o]+=v; else { int M = (L + R)>>1; if (le<=M) update(o<<1,L,M,le,ri); if (ri>M) update(o<<1|1,M+1,R,le,ri); } } 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 gcd(int x,int y) { if (x==0) return y; return gcd(y%x,x); } int main() { int T,m,ca=0,cnt=0; for (int i=1;i<=1000;i++) for (int j=1;j<=1000;j++) if (gcd(i,j)==1) {sl[++cnt].a=i;sl[cnt].b=j;} sl[++cnt].a=1; sl[cnt].b=1000005; sl[0].a=1; sl[0].b=0; sort(sl+1,sl+1+cnt,cmp2); for (int i=1;i<=cnt;i++) { for (int j=1;(sl[i].a*j<=1000)&&(sl[i].b*j<=1000);j++) t[sl[i].a*j][sl[i].b*j]=i; } 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(); } memset(addv,0,sizeof addv); sort(q+1,q+m+1,cmp); int pt=0,r,c,le,ri,mid; for (int i=1;i<=m;i++) { while (q[i].p>=(pt/1000+1)&&pt<1000000) { pt++; r=(pt-1)/1000+1; c=(pt%1000)?(pt%1000):1000; v=(r+A)*(c+B); update(1,1,cnt,t[r][c],cnt); } tmp.a=q[i].a; tmp.b=q[i].b; le=0; ri=cnt; while (ri-le) { mid=(ri+le)>>1; if (cmp2(tmp,sl[mid])==0) le=mid+1; else ri=mid; } le--; ans[q[i].r]=quer(le,1,1,cnt); } printf("Case #%d:\n",++ca); for (int i=1;i<=m;i++) printf("%I64d\n",ans[i]); } return 0; }
第二版 2859ms
#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; }