其他分享
首页 > 其他分享> > 【USACO 2022FEB P】Paint by Rectangles

【USACO 2022FEB P】Paint by Rectangles

作者:互联网

【USACO 2022FEB P】Paint by Rectangles

by AmanoKumiko

Description

在她之前的作品受到好评后,Bessie 得到了一份设计绘画套装的工作。她通过在平面中选择 \(N\ (1\le N\le 10^5)\) 个平行于坐标轴的矩形来设计该画作,没有两条边是共线的。这些矩形的边界定义了绘画着色区域的边界。

作为一名先锋艺术家,Bessie 觉得这幅画应该像一头荷斯坦奶牛。更具体地,由矩形构成的每个区域都被着色为黑色或白色,没有两个相邻区域具有相同的颜色,并且所有矩形之外的区域都被着色为白色。

选完矩形后,Bessie 想根据参数 \(T\) 让你输出:

若 \(T=1\),则输出区域总数;

若 \(T=2\),则依次输出白色区域数量和黑色区域数量。

Input

第一行,输入 \(N\) 和 \(T\)。

接下来 \(N\) 行,每行读入 \(x_1,y_1,x_2,y_2\),表示一个左下角为 \((x_1,y_1)\),右上角为 \((x_2,y_2)\) 的矩形。

数据保证 \(x_i\) 形成了一个 \(1\sim 2N\) 的排列,\(y_i\) 同理。

Output

若 \(T=1\),输出一个整数;否则输出两个整数,用空格隔开。

Sample Input

2 1
1 1 3 3
2 2 4 4

Sample Output

4

Data Constraint

\(1\le N\le 10^5\)

Solution

我们有平面图欧拉定理\(V-E+F=C+1\)

设有\(X\)个交点,就可以改写成\(F=X+C+1\)

交点可以直接扫描线

考虑算联通块

我们使用线段树上并查集

如果一个区间内存在线段,就打上标记,否则退出

如果已经存在标记了,就进行合并

标记在矩形的最左侧和最右侧都要打

然后考虑算黑色区域数

首先是插入线段,根据颜色(线段数量的奇偶性决定)分讨

然后是删除线段,这个时候要对外面的区域进行合并,同理分讨一下

但是发现一个问题,在出现套娃的时候,会多减掉一个黑色区域

不过研究表明,这对于一个联通块来说,最多只会有一次

于是我们可以在每个矩形的左下角记录颜色

在合并联通块的时候对最左边的矩形的颜色进行判定,如果是黑色就加回来

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define N 200010

LL X,C,F,B;
int n,T,L[N],R[N],op[N],f[N],col[N];
struct node{int lx,ly,rx,ry;}a[N];

int find(int x){return f[x]==x?x:(f[x]=find(f[x]));}

void merge(int x,int y){int A=find(x),B=find(y);if(A!=B)f[A]=B;}

struct tree{
	#define ls x<<1
	#define rs (x<<1)|1
	int tag[N*4],sum[N*4];
	void pushdown(int x){
		if(!tag[x])return;
		if(sum[ls]){
			if(!tag[ls])tag[ls]=tag[x];
			else merge(tag[ls],tag[x]);
		}
		if(sum[rs]){
			if(!tag[rs])tag[rs]=tag[x];
			else merge(tag[rs],tag[x]);
		}
		tag[x]=0;
	}
	void pushup(int x){sum[x]=sum[ls]+sum[rs];}
	void modify(int x,int l,int r,int ll,int rr,int pos){
		if(r<ll||l>rr)return;
		if(l>=ll&&r<=rr){
			if(!sum[x])return;
			if(!tag[x])tag[x]=pos;
			else merge(tag[x],pos);
			return;
		}
		int mid=l+r>>1;
		pushdown(x);
		modify(ls,l,mid,ll,rr,pos);modify(rs,mid+1,r,ll,rr,pos);
		pushup(x);
	}
	void change(int x,int l,int r,int k,int pos){
		if(l==r){
			if(k==1)sum[x]++;
			else sum[x]--,tag[x]=0;
			return;
		}
		int mid=l+r>>1;
		pushdown(x);
		pos<=mid?change(ls,l,mid,k,pos):change(rs,mid+1,r,k,pos);
		pushup(x);
	}
	int query(int x,int l,int r,int ll,int rr){
		if(r<ll||l>rr)return 0;
		if(l>=ll&&r<=rr)return sum[x];
		int mid=l+r>>1;
		return query(ls,l,mid,ll,rr)+query(rs,mid+1,r,ll,rr);
	}
}t;

vector<int>S[N];

int main(){
	scanf("%d%d",&n,&T);
	F(i,1,n){
		f[i]=i;
		scanf("%d%d%d%d",&a[i].lx,&a[i].ly,&a[i].rx,&a[i].ry);
		op[a[i].lx]=i;op[a[i].rx]=-i;
		L[a[i].lx]=L[a[i].rx]=a[i].ly;R[a[i].lx]=R[a[i].rx]=a[i].ry;
	}
	F(i,1,2*n){
		if(op[i]>0){
			t.change(1,1,n*2,1,L[i]);t.change(1,1,n*2,1,R[i]);
			t.modify(1,1,n*2,L[i],R[i],op[i]);
			int q=t.query(1,1,n*2,L[i]+1,R[i]-1),d=t.query(1,1,n*2,1,L[i]-1)+1;
			d&1?B+=(q>>1)+1:B+=q+1>>1;
			X+=q;
			col[i]=d&1;
		}else{
			t.change(1,1,n*2,-1,L[i]);t.change(1,1,n*2,-1,R[i]);
			t.modify(1,1,n*2,L[i],R[i],-op[i]);
			int q=t.query(1,1,n*2,L[i]+1,R[i]-1);
			int u=t.query(1,1,n*2,R[i]+1,n*2)+1,d=t.query(1,1,n*2,1,L[i]-1)+1;
			// Black 1,White 0
			if((d&1)&&(u&1))B+=q>>1;
			else if(!(d&1)&&!(u&1))B+=(q>>1)-1;
			else B+=(q+1>>1)-1;
			X+=q;
		}
	}
	F(i,1,n){if(find(i)==i)C++;S[find(i)].push_back(a[i].lx);}
	F(i,1,n)if(find(i)==i){
		int tx=n*2+1,pos;
		for(auto d:S[i])if(d<tx)tx=d,pos=d;
		if(!col[pos])B++;
	}
	F=X+C+1;
	if(T==1)printf("%lld",F);
	else printf("%lld %lld",F-B,B);
	return 0;
}

标签:int,ll,Paint,query,2022FEB,矩形,Rectangles,find,lx
来源: https://www.cnblogs.com/AmanoKumiko/p/16379946.html