#树状数组,CDQ分治#洛谷 4390 [BOI2007]Mokia 摩基亚

题目


分析

考虑离线处理,那么询问区间和就可以转换为四个询问,
CDQ分治按横坐标处理询问,树状数组维护前缀和就可以了


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=2000011,M=200011;
struct rec{int x,X,Y;}q[M],Q[M];
int c[N],n,ans[M],CNT,TOT;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline signed query(int x){rr int ans=0; for (;x;x-=-x&x) ans+=c[x]; return ans;}
inline void CDQ(int l,int r){
	if (l==r) return;
	rr int mid=(l+r)>>1,i=l,j=mid+1,Cnt=0; 
	CDQ(l,mid),CDQ(mid+1,r);
	for (;j<=r;++j){
		for (;i<=mid&&q[i].X<=q[j].X;++i){
		    if (q[i].x>1e4) add(q[i].Y,q[i].x-1e4);
	        Q[++Cnt]=q[i];
		}
		if (q[j].x<=1e4){
			if (q[j].x<0) ans[-q[j].x]-=query(q[j].Y);
			    else ans[q[j].x]+=query(q[j].Y);
		}
		Q[++Cnt]=q[j];
	}
	for (rr int I=l;I<i;++I)
	    if (q[I].x>1e4)
		    add(q[I].Y,1e4-q[I].x);
	for (rr int I=i;I<=mid;++I) Q[++Cnt]=q[I];
	for (rr int I=l;I<=r;++I) q[I]=Q[I-l+1];
}
signed main(){
    iut(),n=iut();
    for (rr int z=iut();z!=3;z=iut()){
    	if (z==1){
    		rr int x=iut(),y=iut(),w=iut();
    		q[++CNT]=(rec){w+1e4,x,y};
		}else{
			rr int lx=iut(),ly=iut(),rx=iut(),ry=iut();
			++TOT,q[++CNT]=(rec){TOT,rx,ry};
			if (lx>1&&ly>1) q[++CNT]=(rec){TOT,lx-1,ly-1};
			if (lx>1) q[++CNT]=(rec){-TOT,lx-1,ry};
			if (ly>1) q[++CNT]=(rec){-TOT,rx,ly-1};
		}
	}
	CDQ(1,CNT);
	for (rr int i=1;i<=TOT;++i)
	    print(ans[i]),putchar(10);
	return 0;
} 
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13820722.html