bzoj2683: 简单题

题目大意:给你一个N*N(N<=500000)的矩阵,支持单点修改,询问子矩阵的和。

思路:CDQ分治的第一题。前半部分和后半部分分别递归处理,然后处理前半部分的修改对后半部分询问的影响,这也是CDQ分治与一般的分治不同的地方。第一维排序,第二维用树状数组维护。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500010,maxm=200010; 
int n,m,cnt,ans[maxm<<2],pos[maxm],op,x1,x2,y1,y2;
struct Tdata{
	int t,x,y,v,id;
	bool operator <(const Tdata &b)const{return x<b.x;}
}que[maxm<<2];

struct Tbit{
	int t[maxn];
	void modify(int x,int v){for (int p=x;p<=n;p+=p&-p) t[p]+=v;}
	int query(int x){int res=0;for (int p=x;p;p-=p&-p) res+=t[p];return res;}
}T;

void cdq_solve(int l,int r){
	if (l==r) return;
	int mid=(l+r)>>1;
	cdq_solve(l,mid),cdq_solve(mid+1,r);
	sort(que+l,que+1+mid),sort(que+mid+1,que+r+1);
	int i=l,j=mid+1,last=0;
	while (j<=r){
		while (que[i].t==2&&i<=mid) ++i;
		while (que[j].t==1&&j<=r) ++j;
		if (i<=mid&&que[i].x<=que[j].x) T.modify(que[i].y,que[i].v),last=i++;
		else if (j<=r) ans[que[j].id]+=T.query(que[j].y),++j;
	}
	for (int i=l;i<=last;i++) if (que[i].t==1) T.modify(que[i].y,-que[i].v);
}

int main(){
	scanf("%d",&n);
	for (;;){
		scanf("%d",&op);
		if (op==1){
			que[++m].t=op,que[m].id=m;
			scanf("%d%d%d",&que[m].x,&que[m].y,&que[m].v);
		}
		else if (op==2){
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			pos[++cnt]=m;
			que[++m].t=op,que[m].id=m,que[m].x=x2,que[m].y=y2;
			que[++m].t=op,que[m].id=m,que[m].x=x1-1,que[m].y=y1-1;
			que[++m].t=op,que[m].id=m,que[m].x=x1-1,que[m].y=y2;
			que[++m].t=op,que[m].id=m,que[m].x=x2,que[m].y=y1-1;
		}
		else break;
	}
	cdq_solve(1,m);
	for (int i=1,p=pos[i];i<=cnt;i++,p=pos[i])
		printf("%d
",ans[p+1]+ans[p+2]-ans[p+3]-ans[p+4]);
	return 0;
}


原文地址:https://www.cnblogs.com/thythy/p/5493592.html