个人理解CDQ就是降维用的…
就比如这道题,一个询问可以拆成四个
把所有的问题分治,用归并排序的思想将
l
l
~和
mid+1
m
i
d
+
1
~
r
r
都按这一维排好序,就可以算作把
x
x
这一维降掉
考虑左区间对右区间的影响,对于右区间的某次询问左区间的所有
x≤x1
x
≤
x
1
的修改都可能对其产生影响
换句话说,对于单次询问
x1,y1
x
1
,
y
1
,事实上只考虑在他之前的,所有
x≤x1
x
≤
x
1
的询问就可以了
那么枚举右区间的查询操作
i
i
,并按从小到大的顺序向树状数组中添加左区间的修改操作,同时满足树状数组里所有修改操作的
x
x
均小于等于这个询问的,那么这个询问的解就加上树状数组的
Query(y)
Q
u
e
r
y
(
y
)
,这个
Query(y)
Q
u
e
r
y
(
y
)
意义就是本层左区间的影响,又因为左右区间都已经用归并的方式将其按照
x
x
<script id="MathJax-Element-17" type="math/tex">x</script>排了序,所以搞个双指针扫一遍就可以了
说的不是很清楚,还是看代码理解吧…
代码如下:
#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define INF 2147483647
#define N 2000050
using namespace std;
inline int read(){
int x=0,f=1;char c;
do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
int n,s,x,y,x1,y1,k,opt,top,Timer;
int a[N],time[N];
struct Data{
int x,y,k,num,ans;
Data(int _x=0,int _y=0,int _k=0,int _num=0,int _ans=0):x(_x),y(_y),k(_k),num(_num),ans(_ans){}
}q[N],b[N];
inline bool cmp(Data a,Data b){
return a.num<b.num;
}
inline void Add(int x,int v){///树状数组修改
for(;x<=n;x=x+(x&-x)){
if(time[x]!=Timer){
time[x]=Timer;
a[x]=0;
}
a[x]=a[x]+v;
}
}
inline int Query(int x){///树状数组查询
int tmp=0;
for(;x;x=x-(x&-x))
if(time[x]==Timer)
tmp=tmp+a[x];
return tmp;
}
void CDQ(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
CDQ(l,mid);CDQ(mid+1,r);///分治左右区间
Timer++;///清空树状数组,memset会超时故使用时间戳
int j=l,i=mid+1;///i扫右区间,j扫左区间
for(;i<=r;i++){
while(q[j].x<=q[i].x && j<=mid){///将左区间x小于当前询问x的修改都落实
if(q[j].k!=INF) Add(q[j].y,q[j].k);///q[j].k==INF代表是查询操作
j++;
}
if(q[i].k==INF) q[i].ans+=Query(q[i].y);///加上本层左区间的影响
}
i=l;j=mid+1;///下面全是归并排序
int top=l;
while(i<=mid && j<=r){
if(q[i].x<q[j].x) b[top++]=q[i++];
else b[top++]=q[j++];
}
while(i<=mid) b[top++]=q[i++];
while(j<=r) b[top++]=q[j++];
for(int i=l;i<=r;i++)
q[i]=b[i];
return;
}
int main(){
s=read();n=read();
while(""){
opt=read();
if(opt==3) break;
if(opt==1){
x=read();y=read();k=read();
top++;q[top]=Data(x,y,k,top,0);
}
else{
x=read();y=read();x1=read();y1=read();
top++;q[top]=Data(x1,y1,INF,top,x1*y1*s);///拆询问
top++;q[top]=Data(x-1,y-1,INF,top,(x-1)*(y-1)*s);
top++;q[top]=Data(x-1,y1,INF,top,(x-1)*y1*s);
top++;q[top]=Data(x1,y-1,INF,top,x1*(y-1)*s);
}
}
CDQ(1,top);
sort(q+1,q+top+1,cmp);
for(int i=1;i<=top;i++)
if(q[i].k==INF){
printf("%d\n",q[i].ans+q[i+1].ans-q[i+2].ans-q[i+3].ans);///统计答案
i=i+3;
}
return 0;
}