【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