【题目描述】
摩尔瓦多的移动电话公司摩基亚(
在定位系统中,世界被认为是一个
请帮助Mokia公司编写一个程序来计算在某个矩形区域内有多少名用户。
【输入格式】
有三种命令,意义如下:
命令 | 参数 | 意义 |
0 | W | 初始化一个全零矩阵。本命令仅开始时出现一次。 |
1 | x y A | 向方格 |
2 | X1 Y1 X2 Y2 | 查询 |
3 | 无参数 | 结束程序。本命令仅结束时出现一次。 |
【输出格式】
对所有命令2,输出一个一行整数,即当前询问矩形内的用户数量。
【输入样例】
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
【输出样例】
3
5
【提示】
输入 | 输出 | 意义 |
0 4 | 大小为 |
|
1 2 3 3 | 向 |
|
2 1 1 3 3 | 查询矩形 |
|
3 | 查询结果 | |
1 2 2 2 | 向 |
|
2 2 2 3 4 | 查询矩形 |
|
5 | 查询结果 | |
3 | 终止程序 |
【数据规模】
命令1不超过
命令2不超过
第一个CDQ,听了已到THU的gg讲的CDQ,表示比较懵X,然后zzh大佬过来告诉我,对于一块矩阵,对他造成影响的修改的因素有两条;1:修改时间比查询时间早 2:x,y范围在此矩阵内,那么我们把query(x1,y1,x2,y2)拆成4个矩阵(x1-1,y1-1)+(x2,y2)-(x1-1,y2)-(x2,y1-1);那么我们对每个操作按x排序,这样就保证了x有序,再用一个树状数组来维护y轴,就保证了第二个条件,那么就可以分治了,在分治到时间(l,r)(其实就是第l到第r个操作)时,考虑(l,mid)中修改操作对(mid+1,r)中查询操作的影响,计算贡献,然后把时间在(l,mid)的放到前半个数组,(mid+1,r)的放在后半个数组(类似于归并排序),然后继续分治下去
然后是助以理解的code:
#define MAXN 2000005 #define lowbit(x) ((x)&(-x)) #include <bits/stdc++.h> using namespace std; int n,m,op,tot,cnt,Ans[MAXN],tree[MAXN]; template<typename _t> inline _t read(){ _t x=0; int f=1; char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f; for(;ch<='9'&&ch>='0';ch=getchar())x=x*10+(ch^48); return (_t)x*f; } struct pa{ int id,op,x,y,w,pos; bool operator < (const pa &a)const{//修改的优先级大于查询 if(x==a.x&&y==a.y)return op<a.op; return x==a.x?y<a.y:x<a.x; } }a[MAXN],temp[MAXN]; void updata(int x,int w){ for(;x<=n;x+=lowbit(x))tree[x]+=w; } int qsum(int x){ int ans = 0; for(;x;x-=lowbit(x))ans+=tree[x]; return ans; } void Add(){ int x1= read<int>(),y1=read<int>(); int x2=read<int>(),y2=read<int>();++cnt; a[++tot].pos=cnt;a[tot].x=x1-1;a[tot].y=y1-1;a[tot].w=1 ;a[tot].op=1; a[++tot].pos=cnt;a[tot].x=x2; a[tot].y=y2; a[tot].w=1 ;a[tot].op=1; a[++tot].pos=cnt;a[tot].x=x1-1;a[tot].y=y2; a[tot].w=-1;a[tot].op=1; a[++tot].pos=cnt;a[tot].x=x2; a[tot].y=y1-1;a[tot].w=-1;a[tot].op=1; } void CDQ(int l,int r){ if(l==r)return; int mid=l+r>>1,l1=l,l2=mid+1; for(int i=l;i<=r;i++){ if(a[i].id<=mid&&a[i].op==0)updata(a[i].y,a[i].w); if(a[i].id>mid&&a[i].op)Ans[a[i].pos]+=qsum(a[i].y)*a[i].w; } for(int i=l;i<=r;i++)if(a[i].id<=mid&&a[i].op==0)updata(a[i].y,-a[i].w); for(int i=l;i<=r;i++){ if(a[i].id<=mid)temp[l1++]=a[i];//把时间在(l,mid)的放在前一半 else temp[l2++]=a[i]; } for(int i=l;i<=r;i++)a[i]=temp[i]; CDQ(l,mid);CDQ(mid+1,r); } int main(){ freopen("mokia.in","r",stdin); freopen("mokia.out","w",stdout); n=read<int>();n=read<int>(); while(1){ op=read<int>(); if(op==1){ a[++tot].x=read<int>(); a[tot].y=read<int>(); a[tot].w=read<int>(); } else if(op==2)Add(); else break; } for(int i=1;i<=tot;i++)a[i].id=i; sort(a+1,a+1+tot); CDQ(1,tot); for(int i=1;i<=cnt;i++)printf("%d ",Ans[i]); }