Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
雁过留声——树状数组+排序扫描为了统计 | 1 | 2 |(x,y) -----+-------- | 3 | 4 | 这4块的面积,实质是要统计以下3个值: S1=横坐标<x的点的个数 S2=纵坐标<y的点的个数 S3=横坐标<x且纵坐标<y的点的个数 那么答案=Abs(N+4*S3-2*S1-2*S2) S1、S2只需要一遍排序就可以离线统计出来了。 S3的统计方法为: 所有点、查询按横坐标排序, 依次扫描,遇到点就把点的纵坐标插入到一个树状数组中去, 遇到查询就从树状数组中查询纵坐标满足范围的数。 为了节省时间,我使用的是基数排序+1行版树状数组。 另外,由于点的坐标的范围都是[0,500000],所以很多地方我都用了一些 “资源消耗”型的解决方案。 示例代码: void RadixSort(){ memset(cnt,0,sizeof(cnt)); for (int i=0;i<N;i++)cnt[X[i]]++; for (int i=1;i<LMax;i++)cnt[i]+=cnt[i-1]; for (int i=N-1;i>=0;i--){ Cx[--cnt[X[i]]]=X[i];//数组多次利用,节约资源 Cy[cnt[X[i]]]=Y[i]; } memcpy(X,Cx,N*sizeof(int)); memcpy(Y,Cy,N*sizeof(int)); memset(cnt,0,sizeof(cnt)); for (int i=0;i<M;i++)cnt[Qx[i]]++; for (int i=1;i<LMax;i++)cnt[i]+=cnt[i-1]; for (int i=M-1;i>=0;i--){ Cx[--cnt[Qx[i]]]=Qx[i]; Cy[cnt[Qx[i]]]=Qy[i]; tmp[cnt[Qx[i]]]=id[i]; } memcpy(Qx,Cx,M*sizeof(int)); memcpy(Qy,Cy,M*sizeof(int)); memcpy(id,tmp,M*sizeof(int)); } memset(Cx,0,sizeof(Cx));memset(Cy,0,sizeof(Cy)); scanf("%d %d",&N,&M); for (int i=0;i<N;i++){ scanf("%d %d",X+i,Y+i); Cx[X[i]]++;Cy[Y[i]]++; } for (int i=1;i<LMax;i++)Cx[i]+=Cx[i-1],Cy[i]+=Cy[i-1]; for (int i=0;i<M;i++){ scanf("%d %d",Qx+i,Qy+i); id[i]=i;ans[i]=-(Cx[Qx[i]]<<1)-(Cy[Qy[i]]<<1)+N; } RadixSort(); memset(tree,0,sizeof(tree)); int j,ret; j=0; for (int i=0;i<M;i++){ while (j<N && X[j]<Qx[i]){ for (int x=Y[j];x<LMax;x+=((x+1)&-(x+1)))tree[x]++;//这就是1行版树状数组 j++; } ret=0; for (int x=Qy[i];x>=0;x-=((x+1)&-(x+1)))ret+=tree[x]; ans[id[i]]+=(ret<<2); } for (int i=0;i<M;i++)printf("%d\n",Abs(ans[i])); Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator