| ||||||||||
| 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