您的位置:首页 > 其它

BZOJ 1176 && BZOJ 2683 CDQ分治

2017-01-05 17:11 513 查看
双倍经验题…放到一起了

CDQ分治

也叫做时间分治。即把操作序列按照一定的顺序排序之后以时间为界进行分治。

算法过程

1.递归处理左、右区间内部修改对询问的影响。

2.处理左区间修改对右区间询问的影响。

(因为不理解这里看了好久…)

这样做可以保证每一个询问之前的修改都会影响到它的答案。

比如这道题

题目大意:给定一个n*n的矩阵(初始全0),有以下操作:

1.把(x,y)处加上z

2.询问(x1,y1)到(x2,y2)的矩形权值和

n<=100000

矩形很大,二维树状数组不能用了。这时我们使用CDQ分治。

CDQ分治常用于把多维问题减少一维。

首先,把操作全都存起来,需要记录操作类型,x/y坐标,操作相关值。

其中,一个询问可以拆成四个询问。

将其按照x坐标排序,进行分治。

分治过程同上,详细见代码。

这里贴上1176的代码

#include <cstdio>
#include <algorithm>
#define N 200005
using namespace std;
inline int lowbit(int x) {return x & -x;}
struct Operation {
int x,y,mode,pos,num;
Operation(){}
Operation(int X,int Y,int Mode,int Pos,int Num):x(X),y(Y),mode(Mode),pos(Pos),num(Num){}
bool operator < (const Operation& rhs) const {return x<rhs.x;}
}p
,sup
;
int n,top,T;
int c[N*10],k[N*10];
void Change(int x,int v) {
while(x<=n) {
if(k[x]!=T) c[x]=0;
k[x]=T;
c[x]+=v;
x+=lowbit(x);
}
return ;
}
int Query(int x) {
int ans=0;
while(x) {
if(k[x]==T) ans+=c[x];
x-=lowbit(x);
}
return ans;
}
bool cmp(const Operation& x,const Operation& y) {return x.pos<y.pos;}
void CDQ(int l,int r) {
if(l==r) return ;
int mid=l+r>>1;
int l1=l,l2=mid+1;
for(int i=l;i<=r;i++)
if(p[i].pos<=mid) sup[l1++]=p[i];
else sup[l2++]=p[i];
for(int i=l;i<=r;i++) p[i]=sup[i];
CDQ(mid+1,r) , CDQ(l,mid);
l1=l , l2=mid+1; T++;
for(;l2<=r;l2++) {
for(;p[l1].x<=p[l2].x && l1<=mid;l1++)
if(p[l1].mode==1)
Change(p[l1].y,p[l1].num);
if(p[l2].mode==2) p[l2].num+=Query(p[l2].y);
}
l1=l , l2=mid+1;
for(int i=l;i<=r;i++)
if(p[l1]<p[l2] && l1<=mid || l2>r) sup[i]=p[l1++];
else sup[i]=p[l2++];
for(int i=l;i<=r;i++) p[i]=sup[i];
return ;
}
int main() {
scanf("%d%d",&n,&n);
int mode;
while(scanf("%d",&mode)==1 && mode!=3) {
if(mode==1) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
p[++top]=Operation(x,y,1,top,z);
}
if(mode==2) {
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
p[++top]=Operation(x1-1,y1-1,2,top,0);
p[++top]=Operation(x2,y1-1,2,top,0);
p[++top]=Operation(x1-1,y2,2,top,0);
p[++top]=Operation(x2,y2,2,top,0);
}
}
sort(p+1,p+1+top);
CDQ(1,top);
sort(p+1,p+1+top,cmp);
for(int i=1;i<=top;i++)
if(p[i].mode==2){
int ans=0;
ans+=p[i++].num;
ans-=p[i++].num;
ans-=p[i++].num;
ans+=p[i].num;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法