COGS1752. [BOI2007]摩基亚Mokia(CDQ,树状数组)
题目描述
摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统。和其他的定位系统一样,它能够迅速回答任何形如“用户C的位置在哪?”的问题,精确到毫米。但其真正高科技之处在于,它能够回答形如“给定区域内有多少名用户?”的问题。
在定位系统中,世界被认为是一个W×W的正方形区域,由1×1的方格组成。每个方格都有一个坐标(x,y),1<=x,y<=W。坐标的编号从1开始。对于一个4×4的正方形,就有1<=x<=4,1<=y<=4(如图):
请帮助Mokia公司编写一个程序来计算在某个矩形区域内有多少名用户。
输入输出格式
输入格式:
有三种命令,意义如下:
命令 参数 意义
- 0 W 初始化一个全零矩阵。本命令仅开始时出现一次。
- 1 x y A 向方格(x,y)中添加A个用户。A是正整数。
- 2 X1 Y1 X2 Y2 查询X1<=x<=X2,Y1<=y<=Y2所规定的矩形中的用户数量
- 3 无参数 结束程序。本命令仅结束时出现一次。
输出格式:
对所有命令2,输出一个一行整数,即当前询问矩形内的用户数量。
输入输出样例
说明
对于所有数据:
1<=W<=2000000
1<=X1<=X2<=W
1<=Y1<=Y2<=W
1<=x,y<=W
0<A<=10000
命令1不超过160000个。
命令2不超过10000个。
题解
树状数组没有清空结果调了几个小时……快疯了……
坐标范围太大,先考虑离散
我们把一个操作看成$(a,x,y)$的形式,其中$a$代表时间,$x,y$代表坐标(查询操作可以通过差分拆成四个操作)
然后就是一个三维偏序问题了,用CDQ+树状数组解决
时间这一维是默认有序的
$x$这一维可以用CDQ自带的归并排好序
$y$这一维用树状数组就可以求出答案
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 6 char buf[1<<21],*p1=buf,*p2=buf; 7 inline int read(){ 8 #define num ch-'0' 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getc())) 11 (ch=='-')&&(flag=true); 12 for(res=num;isdigit(ch=getc());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 char sr[1<<21],z[20];int C=-1,Z; 18 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 19 inline void print(int x){ 20 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 21 while(z[++Z]=x%10+48,x/=10); 22 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 23 } 24 const int N=200005; 25 struct node{ 26 int x,y,d,id; 27 inline void add(int a,int b,int c,int _id=0) 28 {x=a,y=b,d=c,id=_id;} 29 inline bool operator <(const node &b)const{ 30 return x!=b.x?x<b.x: 31 y!=b.y?y<b.y: 32 d>b.d; 33 } 34 }a[N],p[N];int n,m,ans[N]; 35 int c[N*10]; 36 inline void add(int x,int val){ 37 for(int i=x;i<=n;i+=i&(-i)) 38 c[i]+=val; 39 } 40 inline int query(int x){ 41 int res=0; 42 for(int i=x;i;i-=i&(-i)) 43 res+=c[i]; 44 return res; 45 } 46 inline void clear(int x){ 47 for(int i=x;i<=n;i+=i&(-i)) 48 if(c[i]) c[i]=0; 49 else return; 50 } 51 void cdq(int l,int r){ 52 if(l==r) return; 53 int mid=(l+r)>>1; 54 cdq(l,mid),cdq(mid+1,r); 55 int i=l,j=l,k=mid+1; 56 while(j<=mid&&k<=r){ 57 if(p[j]<p[k]){ 58 if(p[j].d) add(p[j].y,p[j].d); 59 a[i++]=p[j++]; 60 } 61 else{ 62 if(!p[k].d) ans[p[k].id]+=query(p[k].y); 63 a[i++]=p[k++]; 64 } 65 } 66 while(j<=mid) a[i++]=p[j++]; 67 while(k<=r){ 68 if(!p[k].d) ans[p[k].id]+=query(p[k].y); 69 a[i++]=p[k++]; 70 } 71 for(int i=l;i<=r;++i){ 72 clear(a[i].y);p[i]=a[i]; 73 } 74 } 75 int main(){ 76 //freopen("testdata.in","r",stdin); 77 n=read(),n=read(); 78 for(int x,y,xx,yy,opt;(opt=read())!=3;){ 79 x=read(),y=read(),xx=read(); 80 if(opt&1){ 81 p[++m].add(x,y,xx,m+1); 82 ans[m]=-1; 83 } 84 else{ 85 yy=read(); 86 p[++m].add(xx,yy,0,m+1),p[++m].add(x-1,yy,0,m+1); 87 p[++m].add(xx,y-1,0,m+1),p[++m].add(x-1,y-1,0,m+1); 88 } 89 } 90 cdq(1,m); 91 for(int i=1;i<=m;++i) 92 if(~ans[i]){ 93 int k=ans[i]-ans[i+1]-ans[i+2]+ans[i+3]; 94 print(k);i+=3; 95 } 96 Ot(); 97 return 0; 98 }
深深地明白自己的弱小