Codechef :Rectangle Query/QRECT (容斥+树套树)

传送门

题解:
CDQ分治什么不存在的。

直接找不相交的,然后分八种情况维护一下即可。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=1e5+50;

int n,tot,id[N];
int totx,toty;
struct matrix {
	int l,r,u,d,v;
} mat[N];
struct ST_1D {
	int rt,tot,lc[N*60],rc[N*60],sze[N*60];
	inline void add(int &k,int l,int r,int p,int v) {
		if(!k) k=++tot; sze[k]+=v;
		if(l==r) return;
		int mid=(l+r)>>1;
		(p<=mid) ? add(lc[k],l,mid,p,v) : add(rc[k],mid+1,r,p,v);
	}
	inline int ask(int k,int l,int r,int L,int R) {
		if(l>r) return 0;
		if(!sze[k]) return 0;
		if(L<=l && r<=R) return sze[k];
		int mid=(l+r)>>1;
		if(R<=mid) return ask(lc[k],l,mid,L,R);
		else if(L>mid) return ask(rc[k],mid+1,r,L,R);
		else return ask(lc[k],l,mid,L,R)+ask(rc[k],mid+1,r,L,R);
	}
	inline void add(int x,int v) {add(rt,1,max(totx,toty),x,v);}
	inline int ask(int l,int r) {return ask(rt,1,max(totx,toty),l,r);}
} s1[4];

struct ST_2D {
	int rt[N*2],lc[N*300],rc[N*300],sze[N*300],tot;
	inline void add(int &k,int l,int r,int p,int v) {
		if(!k) k=++tot; sze[k]+=v;
		if(l==r) return;
		int mid=(l+r)>>1;
		(p<=mid) ? add(lc[k],l,mid,p,v) : add(rc[k],mid+1,r,p,v);
	}
	inline int ask(int k,int l,int r,int L,int R) {
		if(!sze[k]) return 0;
		if(L<=l && r<=R) return sze[k];
		int mid=(l+r)>>1;
		if(R<=mid) return ask(lc[k],l,mid,L,R);
		else if(L>mid) return ask(rc[k],mid+1,r,L,R);
		else return ask(lc[k],l,mid,L,R)+ask(rc[k],mid+1,r,L,R);
	}
	inline void add(int x,int y,int v) {
		for(int i=x;i<=totx;i+=i&(-i)) add(rt[i],1,toty,y,v);
	}
	inline int ask(int lx,int rx,int ly,int ry) {
		if(lx>rx || ly>ry) return 0;
		int ans=0;
		for(int i=rx;i;i-=i&(-i)) ans+=ask(rt[i],1,toty,ly,ry);
		for(int i=lx-1;i;i-=i&(-i)) ans-=ask(rt[i],1,toty,ly,ry);
		return ans;
	}
} s2[4];

inline void init() {
	n=rd();
	vector <int> vl;
	vector <int> vu;
	for(int i=1;i<=n;i++) {
		char ch=nc(); while(!isalpha(ch)) ch=nc();
		if(ch=='I') {
			id[++tot]=i;
			mat[i].l=rd(), mat[i].d=rd();
			mat[i].r=rd(), mat[i].u=rd();
			mat[i].v=1;
			vl.push_back(mat[i].l), vl.push_back(mat[i].r);
			vu.push_back(mat[i].u), vu.push_back(mat[i].d);
		} else if(ch=='Q') {
			mat[i].l=rd(), mat[i].d=rd();
			mat[i].r=rd(), mat[i].u=rd();
			mat[i].v=0;
			vl.push_back(mat[i].l), vl.push_back(mat[i].r);
			vu.push_back(mat[i].u), vu.push_back(mat[i].d);
		} else {
			mat[i]=mat[id[rd()]];
			mat[i].v=-1;
		}
	}
	sort(vl.begin(),vl.end()); vl.erase(unique(vl.begin(),vl.end()),vl.end());
	sort(vu.begin(),vu.end()); vu.erase(unique(vu.begin(),vu.end()),vu.end());
	totx=vl.size(); toty=vu.size();
	#define id(x,y) (lower_bound(x.begin(),x.end(),y)-x.begin()+1)
	for(int i=1;i<=n;i++) {
		mat[i].l=id(vl,mat[i].l);
		mat[i].r=id(vl,mat[i].r);
		mat[i].u=id(vu,mat[i].u);
		mat[i].d=id(vu,mat[i].d);
	}
}

int main() {
	init(); int sum=0;
	for(int i=1;i<=n;i++) {
		if(mat[i].v) {
			sum+=mat[i].v;
			s1[0].add(mat[i].r,mat[i].v);
			s1[1].add(mat[i].l,mat[i].v);
			s1[2].add(mat[i].d,mat[i].v);
			s1[3].add(mat[i].u,mat[i].v);
			s2[0].add(mat[i].r,mat[i].d,mat[i].v);
			s2[1].add(mat[i].r,mat[i].u,mat[i].v);
			s2[2].add(mat[i].l,mat[i].d,mat[i].v);
			s2[3].add(mat[i].l,mat[i].u,mat[i].v);
		} else {
			int ans=0;
			ans+=s1[0].ask(1,mat[i].l-1);
			ans+=s1[1].ask(mat[i].r+1,totx);
			ans+=s1[2].ask(mat[i].u+1,toty);
			ans+=s1[3].ask(1,mat[i].d-1);
			ans-=s2[0].ask(1,mat[i].l-1,mat[i].u+1,toty);
			ans-=s2[1].ask(1,mat[i].l-1,1,mat[i].d-1);
			ans-=s2[2].ask(mat[i].r+1,totx,mat[i].u+1,toty);
			ans-=s2[3].ask(mat[i].r+1,totx,1,mat[i].d-1);
			printf("%d\n",sum-ans);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值