qoj1838

给定 \(n\) 个矩形,求有几个三元组 \((i,j,k)\),满足 \((i,j),(j,k),(i,k)\) 没有交,\(n\le2\times 10^5\)

首先先离散化

将矩形看成图,将有交的矩形连边,则要求有多少三元组所对应的三个点之间没有边

考虑容斥,用 \(\binom{n}{3}\) 减去三个点之间有边的情况数,设有一条边的情况数为 \(c_1\),有两条边的情况数为 \(c_2\),有三条边的情况数为 \(c_3\),则答案为 \(\binom{n}{3}-c_1-c_2-c_3\)

设点 \(i\) 的度数为 \(d_i\),考虑每一条边(双向),可得 \((n-2)\sum d_i=2c_1+4c_2+6c_3\)\(\sum\binom{d_i}{2}=c_2+3c_3\),于是可以得到 \(c_1+c_2\)

于是问题变为如何求 \(d_i\)\(c_3\)

怎么求 \(d_i\) 呢?考虑扫描线,经过尝试发现对每个矩阵,访问到上边的时候我们不删除它,那么与它有交的矩阵个数就是上边下面的下边个数减去下边下面的上边个数,这时候自己本身会被多算一次所以要减掉

怎么求 \(c_3\) 呢?将每个符合要求的三元组的贡献挂到 \(x_1\) 最大的那个矩形,称该矩形为 \(a\),其余两个为 \(b,c\)

因为扫描线时有 \({x_1}_b\le{x_1}_a\le{x_2}_b\le{x_1}_a\)\({x_1}_c\le{x_1}_a\le{x_2}_c\le{x_1}_a\),所以 \(b,c\)\(x\) 坐标一定相交,问题变为求有多少 \(b,c\) 满足 \((a,b),(a,c),(b,c)\)\(y\) 坐标都有交

再次容斥,设所有 \(x_1\) 小于 \(a\) 且与 \(a\) 相交的矩形个数为 \(cnt\),则答案为 \(\binom{cnt}{2}\) 减去 \((a,b),(a,c)\)\(y\) 坐标有交但 \((b,c)\) 无交的 \((b,c)\) 数量

不妨 \({y_2}_b<{y_1}_c\),那么只有 \({y_1}_a\le{y_2}_b<{y_1}_c\le{y_2}_a\) 这一种情况,使用线段树即可

#include<bits/stdc++.h>
using namespace std;
namespace ax_by_c{
typedef long long ll;
ll c2(ll x){
	return x*(x-1)/2;
}
ll c3(ll x){
	return x*(x-1)*(x-2)/6;
}
const int N=2e5+5;
int n;
struct BIT{
	int lb(int x){
		return x&(-x);
	}
	ll tr[N*2];
	void add(int i,ll v){
		for(;i<=n*2;i+=lb(i))tr[i]+=v;
	}
	ll q(int i){
		ll r=0;
		for(;i;i-=lb(i))r+=tr[i];
		return r;
	}
}x1y1,x1y2,x2y1,x2y2,try1,try2;
struct seg{
	struct node{
		ll a,b,c;
	}tr[N*8];
	node meg(node x,node y){
		return {x.a+y.a,x.b+y.b,x.c+y.c+x.a*y.b};
	}
	void pu(int u){
		tr[u]=meg(tr[u<<1],tr[u<<1|1]);
	}
	void upda(int u,int l,int r,int pos,ll v){
		if(l==r){
			tr[u].a+=v;
			return ;
		}
		int mid=l+((r-l)>>1);
		if(pos<=mid)upda(u<<1,l,mid,pos,v);
		else upda(u<<1|1,mid+1,r,pos,v);
		pu(u);
	}
	void updb(int u,int l,int r,int pos,ll v){
		if(l==r){
			tr[u].b+=v;
			return ;
		}
		int mid=l+((r-l)>>1);
		if(pos<=mid)updb(u<<1,l,mid,pos,v);
		else updb(u<<1|1,mid+1,r,pos,v);
		pu(u);
	}
	node Q(int u,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return tr[u];
		int mid=l+((r-l)>>1);
		if(qr<=mid)return Q(u<<1,l,mid,ql,qr);
		if(mid+1<=ql)return Q(u<<1|1,mid+1,r,ql,qr);
		return meg(Q(u<<1,l,mid,ql,qr),Q(u<<1|1,mid+1,r,ql,qr));
	}
}tr;
struct node{
	int x1,x2,y1,y2;
	ll d;
}a[N];
int hsh[N*2],hc;
bool cmp(node x,node y){
	return x.y1<y.y1;
}
int xid[N*2];
void main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d %d %d %d",&a[i].x1,&a[i].x2,&a[i].y1,&a[i].y2);
	}
	for(int i=1;i<=n;i++)hsh[++hc]=a[i].x1;
	for(int i=1;i<=n;i++)hsh[++hc]=a[i].x2;
	sort(hsh+1,hsh+1+hc);hc=unique(hsh+1,hsh+1+hc)-hsh-1;
	for(int i=1;i<=n;i++)a[i].x1=lower_bound(hsh+1,hsh+1+hc,a[i].x1)-hsh;
	for(int i=1;i<=n;i++)a[i].x2=lower_bound(hsh+1,hsh+1+hc,a[i].x2)-hsh;
	hc=0;
	for(int i=1;i<=n;i++)hsh[++hc]=a[i].y1;
	for(int i=1;i<=n;i++)hsh[++hc]=a[i].y2;
	sort(hsh+1,hsh+1+hc);hc=unique(hsh+1,hsh+1+hc)-hsh-1;
	for(int i=1;i<=n;i++)a[i].y1=lower_bound(hsh+1,hsh+1+hc,a[i].y1)-hsh;
	for(int i=1;i<=n;i++)a[i].y2=lower_bound(hsh+1,hsh+1+hc,a[i].y2)-hsh;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		xid[a[i].x1]=i;
		xid[a[i].x2]=-i;
	}
	ll C3=0;
	for(int i=1;i<=n*2;i++){
		int u=xid[i];
		if(u<0){
			u=-u;
			tr.upda(1,1,n*2,a[u].y2,-1);
			tr.updb(1,1,n*2,a[u].y1,-1);
			try1.add(a[u].y1,-1);
			try2.add(a[u].y2,-1);
			a[u].d+=x1y1.q(a[u].y2)-x1y2.q(a[u].y1-1);
			x2y1.add(a[u].y1,1);
			x2y2.add(a[u].y2,1);
		}
		else{
			a[u].d-=x2y1.q(a[u].y2)-x2y2.q(a[u].y1-1);
			C3+=c2(try1.q(a[u].y2)-try2.q(a[u].y1-1))-tr.Q(1,1,n*2,a[u].y1,a[u].y2).c;
			x1y1.add(a[u].y1,1);
			x1y2.add(a[u].y2,1);
			try1.add(a[u].y1,1);
			try2.add(a[u].y2,1);
			tr.upda(1,1,n*2,a[u].y2,1);
			tr.updb(1,1,n*2,a[u].y1,1);
		}
	}
	ll ans=c3(n),sum=0;
	for(int i=1;i<=n;i++){
		a[i].d--;
		sum+=a[i].d*(n-2)-c2(a[i].d)*2;
	}
	sum/=2;
	ans-=sum;
	ans-=C3;
	printf("%lld\n",ans);
}
}
int main(){
	ax_by_c::main();
	return 0;
}
posted @ 2024-10-05 19:38  ax_by_c  阅读(119)  评论(0)    收藏  举报