【BOI2007】摩基亚Mokia
P1948 - 【BOI2007】摩基亚Mokia
Description
摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统。和其他的定位系统一样,它能够迅速回答任何形如“用户C的位置在哪?”的问题,精确到毫米。但其真正高科技之处在于,它能够回答形如“给定区域内有多少名用户?”的问题。
在定位系统中,世界被认为是一个W * W的正方形区域,由1 *
1的方格组成。每个方格都有一个坐标(x,y),1<=x,y<=W。坐标的编号从1开始。对于一个4 *
4的正方形,就有1<=x<=4,1<=y<=4(如图):
请帮助Mokia公司编写一个程序来计算在某个矩形区域内有多少名用户。
Input
有三种命令,意义如下:
命令 参数 意义
0 W 初始化一个全零矩阵。本命令仅开始时出现一次。
1 x y A 向方格(x,y)中添加A个用户。A是正整数。
2 X1 Y1 X2 Y2 查询X1<=x<=X2,Y1<=y<=Y2所规定的矩形中的用户数量
3 无参数 结束程序。本命令仅结束时出现一次。
Output
对所有命令2,输出一个一行整数,即当前询问矩形内的用户数量。
Sample Input
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
Hint
样例提示:
输入 输出 意义
0 4 大小为4 * 4的全零正方形
1 2 3 3 向(2,3)方格加入3名用户
2 1 1 3 3 查询矩形1<=x<=3,1<=y<=3内的用户数量
3 查询结果
1 2 2 2 向(2,2)方格加入2名用户
2 2 2 3 4 查询矩形2<=x<=3,2<=y<=4内的用户数量
5 查询结果
3 终止程序
数据规模:
1<=W<=2000000
1<=X1<=X2<=W
1<=Y1<=Y2<=W
1<=x,y<=W
0<A<=10000
命令1不超过160000个。
命令2不超过10000个。
离线处理每个询问,把一个查询操作分解成四个二维前缀和。每个询问维护一个询问时间,一个x坐标,一个y坐标。
设Q为增加,P为查询,只有当Qx<=Px&& Qy<=Py && Qt<=Pt 时才能对P产生贡献,然后就可以用CDQ分治维护三维偏序。
第一维时间直接排序,第二维xCDQ分治,只要计算左区间的增加对右区间的查询的影响,第三维y插入树状数组。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define maxn 2000100 15 using namespace std; 16 struct data{ 17 int t,x,y,da,id; 18 int an,po; 19 }e[maxn]; 20 int LOL=0,co[maxn],tree[maxn],ans[maxn]; 21 int lowbit(int x){return x&-x;} 22 bool cmpcdq(const data &a,const data &b){ 23 if(a.x!=b.x) return a.x<b.x; 24 else return a.y<b.y; 25 } 26 void add(int p,int w){ 27 for(int i=p;i<=maxn;i+=lowbit(i)){ 28 if(co[i]!=LOL) tree[i]=0; 29 co[i]=LOL; 30 tree[i]+=w; 31 } 32 } 33 int find(int p){ 34 if(p==0) return 0; 35 int sum=0; 36 for(int i=p;i;i-=lowbit(i)) 37 if(co[i]==LOL) 38 sum+=tree[i]; 39 return sum; 40 } 41 void CDQ(int l,int r){ 42 if(l==r) return; 43 int mid=(l+r)>>1; 44 CDQ(l,mid),CDQ(mid+1,r); 45 sort(e+l,e+mid+1,cmpcdq);sort(e+mid+1,e+r+1,cmpcdq); 46 LOL++; 47 for(int j=mid+1,i=l;j<=r;j++){ 48 for(;i<=mid && e[i].x<=e[j].x;i++) 49 if(e[i].id==1) 50 add(e[i].y,e[i].da); 51 if(e[j].id==2) 52 e[j].an+=find(e[j].y); 53 } 54 } 55 int main() 56 { 57 freopen("!.in","r",stdin); 58 freopen("!.out","w",stdout); 59 int n,type,t=0,tot=0,ans1=0; 60 scanf("%d",&n),scanf("%d",&n); 61 while(1){ 62 scanf("%d",&type);if(type==3) break; 63 t++;tot++; 64 if(type==1)scanf("%d%d%d",&e[tot].x,&e[tot].y,&e[tot].da),e[tot].id=1,e[tot].t=t; 65 else{ 66 int x,y,xx,yy; 67 ++ans1; 68 scanf("%d%d%d%d",&x,&y,&xx,&yy); 69 e[tot].x=xx,e[tot].y=yy,e[tot].id=2,e[tot].da=1,e[tot].t=t,e[tot].po=ans1;tot++; 70 e[tot].x=xx,e[tot].y=y-1,e[tot].id=2,e[tot].da=2,e[tot].t=t,e[tot].po=ans1;tot++; 71 e[tot].x=x-1,e[tot].y=yy,e[tot].id=2,e[tot].da=3,e[tot].t=t,e[tot].po=ans1;tot++; 72 e[tot].x=x-1,e[tot].y=y-1,e[tot].id=2,e[tot].da=4,e[tot].t=t;e[tot].po=ans1; 73 } 74 } 75 76 CDQ(1,tot); 77 for(int i=1;i<=tot;i++) 78 if(e[i].id==2){ 79 if(e[i].da==1 || e[i].da==4) 80 ans[e[i].po]+=e[i].an; 81 else 82 ans[e[i].po]-=e[i].an; 83 } 84 for(int i=1;i<=ans1;i++) 85 printf("%d\n",ans[i]); 86 return 0; 87 }