BZOJ2683: 简单题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2683: 简单题相关的知识,希望对你有一定的参考价值。

传送门

CDQ分治

cdq分治的练习题,第一次接触这样的离线思路。莫队的离线方法是把区间的询问排序处理。而这个则是把所有询问当成线段来看,把对一个矩阵的询问换成了统计某几个询问对后面几个询问的贡献,非常巧妙的思路。

CDQ分治的基本不说,这个的关键是用CDQ分治来对询问分治。输入数据不变。来维护时间上的单调性。然后对于每一次的区间统计,按$x$的值递增排序。然后对于左区间的每个贡献,统计到右区间。具体的统计方法是用以$y$轴建个树状数组。然后$x$值递增,对于左边的具体贡献及时统计到右区间即可。需要注意的是,直接的矩形询问不好处理。考虑把$(x_1,y_1)$到$(x_2,y_2)$的矩阵拆成$(x_1-1,y_1-1),(x_1-1,y_2),(x_2,y_1-1),(x_2,y_2)$然后容斥原理搞搞就行了。

 

 

//BZOJ 2683
//by Cydiater
//2016.10.12
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <cstdio>
using namespace std;
#define ll long long
#define up(i,j,n)		for(int i=j;i<=n;i++)
#define down(i,j,n)		for(int i=j;i>=n;i--)
const int MAXN=1e6+5;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int N,M=0;
int c[MAXN];
struct Node{
	int x,y,f,id;ll ans;
}a[MAXN],b[MAXN];
namespace solution{
	inline bool re_cmp(Node x,Node y){return x.id<y.id;}
	inline int lowbit(int i){return((i)&(-i));}
	void init(){
		N=read();int f;
		while((f=read())!=3){
			if(f==1){
				int x=read(),y=read(),v=read();
				a[++M]=(Node){x,y,1,M,v};//add point
			}else{
				int A=read(),b=read(),c=read(),d=read();
				int x=min(A,c),y=min(b,d),X=max(A,c),Y=max(b,d);
				a[++M]=(Node){x-1,y-1,0,M,0};a[++M]=(Node){X,y-1,0,M,0};
				a[++M]=(Node){x-1,Y,0,M,0};a[++M]=(Node){X,Y,0,M,0};
			}
		}
	}
	void insert(int pos,int v){for(int i=pos;i<=N;i+=lowbit(i))c[i]+=v;}
	ll get(int pos){
		int tmp=0;
		for(int i=pos;i>=1;i-=lowbit(i))tmp+=c[i];
		return tmp;
	}
	void slove(int leftt,int rightt){
		if(leftt==rightt)return;
		int mid=(leftt+rightt)>>1;
		slove(leftt,mid);slove(mid+1,rightt);
		int point=leftt;
		up(i,mid+1,rightt)if(a[i].f==0){
			int lim=a[i].x;
			while(point<=mid&&a[point].x<=lim){
				if(a[point].f!=1){point++;continue;}
				insert(a[point].y,a[point].ans);
				point++;
			}
			a[i].ans+=get(a[i].y);
		}
		int j=leftt,k=mid+1;
		up(i,leftt,point-1)if(a[i].f==1)insert(a[i].y,-a[i].ans);
		up(i,leftt,rightt)b[i]=((j<=mid&&a[j].x<a[k].x)||k>rightt)?a[j++]:a[k++];
		up(i,leftt,rightt)a[i]=b[i];
	}
	void output(){
		sort(a+1,a+M+1,re_cmp);
		up(i,1,M)if(a[i].f==0){
			ll ans=0;ans=a[i+3].ans-a[i+2].ans-a[i+1].ans+a[i].ans;
			i+=3;
			printf("%d\n",ans);
		}
	}
}
int main(){
	//freopen("input.in","r",stdin);
	using namespace solution;
	init();
	slove(1,M);
	output();
	return 0;
}

以上是关于BZOJ2683: 简单题的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2683 简单题

bzoj 2683: 简单题

BZOJ 2683 简单题

[BZOJ2683][BZOJ4066]简单题

bzoj2683简单题 cdq分治

BZOJ2683: 简单题(CDQ分治 + 树状数组)