【bzoj2683】简单题 CDQ分治+树状数组

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2683

【题解】

话说这题好像可以用整体二分来做(蒟蒻不会啊),CDCQ大神的整体二分比我的CDQ分治高到不知道哪里去了。

说一下做法吧:

首先把询问的矩形分成4部分,算一下每部分的答案,然后容斥原理即可。

怎样算每部分的答案呢?

我们按照时间分治,CDQ递归过程中按x排序,遇到修改则插入到树状数组中,遇到询问就在bit中查询即可。

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 800010
#define up(i,j,n) for(int i=j;i<=n;++i)
#define dn(i,j,n) for(int i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
struct node{
	ll x,y,v,id,opt;
	bool operator <(const node &b)const{return id=r)  return;
	int mid=(l+r)>>1,ta(l),tb(mid+1),top(0);
	CDQ(l,mid);  CDQ(mid+1,r);
	while(ta<=mid&&tb<=r){
		while(ta<=mid&&a[ta].x<=a[tb].x){
			if(a[ta].opt==1) add(a[ta].y,a[ta].v);
			stack[++top]=a[ta++];
		}
		while(tb<=r&&a[ta].x>a[tb].x){
			if(a[tb].opt==2) a[tb].v+=get(a[tb].y);
			stack[++top]=a[tb++];
		}
	}
	while(ta<=mid){
		if(a[ta].opt==1)  add(a[ta].y,a[ta].v);
		stack[++top]=a[ta++];
	}
	while(tb<=r){
		if(a[tb].opt==2)  a[tb].v+=get(a[tb].y);
		stack[++top]=a[tb++];
	}
	up(i,l,mid)  if(a[i].opt==1)  add(a[i].y,-a[i].v);
	up(i,l,r)  a[i]=stack[i-l+1];
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	n=read();
	while(1){
		int opt=read();  
		if(opt==1){
			int x=read(),y=read(),v=read();
			a[++m]=(node){x,y,v,m,opt};
		}
		else if(opt==2){
			int x1=read(),y1=read(),x2=read(),y2=read();
			int X1=min(x1,x2),Y1=min(y1,y2),X2=max(x1,x2),Y2=max(y1,y2);
			a[++m]=(node){X1-1,Y1-1,0,m,opt};
			a[++m]=(node){X1-1,Y2,0,m,opt};
			a[++m]=(node){X2,Y1-1,0,m,opt};
			a[++m]=(node){X2,Y2,0,m,opt};
		}
		else break;
	}
	CDQ(1,m);  sort(a+1,a+m+1);
	up(i,1,m)if(a[i].opt==2)printf("%lld\n",(ll)a[i+3].v-a[i+2].v-a[i+1].v+a[i].v),i+=3;
	return 0;
}




你可能感兴趣的:(bzoj,树状数组,CDQ分治)