bzoj 1176: Mokia CDQ分治

人生第一道自己写的CDQ LOL~~~

题目大意

维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

题解

CDQ分治裸上啊...
啥是CDQ啊?....
怎么说呢..
CDQ分治是一种思想.
将整个序列分成两半递归处理,但是由于左边对右边的序列存在着不可忽略的影响,所以需要在递归时考虑左半边序列对右半边序列的影响。
即CDQ的核心思想.(大概...)
至于具体的实现过程,这种东西还是对着代码比较好学。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxm = 210010;
const int maxn = 2100000;
struct Node{
	int op,x,y;
	int val,id;
	bool friend operator < (const Node &a,const Node &b){
		return a.x < b.x;
	}Node(){}
	Node(int a,int b,int c,int d,int e){op=a;x=b;y=c;val=d;id = e;}
}a[maxm],atmp[maxm];
int cnt,n;
int anss[10010];
int c[maxn],tmp[maxm];
#define lowbit(x) (x&-x)
inline void modify(int x,int y){
	if(!x) return;
	for(;x <= n;x+=lowbit(x)) c[x] += y;
}
inline int query(int x){
	int ret = 0;
	for(;x>=1;x-=lowbit(x)) ret += c[x];
	return ret;
}
inline void merge(int l,int r){
	if(l == r) return;
	int mid = l+r >> 1;
	int i = l,j = mid+1,k = l;
	while(i <= mid || j <= r){
		if(j > r || ( i <= mid && a[i].x < a[j].x)) atmp[k++] = a[i++];
		else atmp[k++] = a[j++];
	}for(int i=l;i<=r;++i) a[i] = atmp[i];
}
void solve(int l,int r){//CDQ的分治
	if(l == r) return ;
	int mid = l+r >> 1;
	solve(l,mid);//递归处理子序列
	solve(mid+1,r);
	merge(l,mid);//对左右序列分别排序
	merge(mid+1,r);
	//下面开始考虑左序列(中的插入操作)对右序列(中的询问操作)的影响
	int p = l,cnt = 0;
	for(int i = mid+1;i<=r;++i){
		if(a[i].op == 2){//如果这是个询问操作
			while(p <= mid && a[p].x <= a[i].x){
				if(a[p].op == 1){//对于左序列所有的操作,更新影响
					tmp[++cnt] = p;
					modify(a[p].y,a[p].val);
				}++p;
			}anss[a[i].id] += a[i].val*query(a[i].y);//做出贡献
		}
	}
	//清空树状数组,注意不能memset
	for(int i=1;i<=cnt;++i) modify(a[tmp[i]].y,-a[tmp[i]].val);
}
int main(){
	read(cnt);read(n);
	int op,x1,y1,x2,y2,x;
	int query_id = 0;
	while(1){
		read(op);if(op == 3) break;
		if(op == 1){
			read(x1);read(y1);read(x);
			a[++cnt] = (Node){op,x1,y1,x,0};
		}else{
			x = ++query_id;
			read(x1);read(y1);read(x2);read(y2);
			//将所有的询问做成前缀和差分的形式
			a[++cnt] = (Node){op,x2,y2,1,x};
			a[++cnt] = (Node){op,x1-1,y2,-1,x};
			a[++cnt] = (Node){op,x2,y1-1,-1,x};
			a[++cnt] = (Node){op,x1-1,y1-1,1,x};
		}
	}
	solve(1,cnt);
	for(int i=1;i<=query_id;++i){
		printf("%d\n",anss[i]);
	}
	getchar();getchar();
	return 0;
}
posted @ 2017-02-15 20:28  Sky_miner  阅读(327)  评论(0编辑  收藏  举报