题意:
给你平面 n n n个矩形,每个矩形有一种颜色,依次给出矩形以及其的颜色,后面的矩形会覆盖前面的矩形,问最终有多少种颜色。
1 ≤ n ≤ 4000 , 0 ≤ x 1 < x 2 < 2 28 , 0 ≤ y 1 < y 2 < 2 28 , 1 ≤ c ≤ n 1\le n\le 4000,0\le x_1<x_2< 2^{28},0\le y_1<y_2< 2^{28},1\le c\le n 1≤n≤4000,0≤x1<x2<228,0≤y1<y2<228,1≤c≤n
思路
首先第一个应该想到的就是倒着来,因为后面的会覆盖前面的。
其次由于坐标范围很大,不难想到离散化一下。
矩阵的问题,很容易往扫描线上靠,让后看一下 n n n,显然可以想到 n 2 l o g n n^2logn n2logn的算法。
矩形扫描线的第一步也是最重要的一步,就是将线段化点,因为矩形如果只存点的话,是显然不对的,比如第三个样例,如果只考虑点的话就会漏掉一种颜色。
让后就是暴力的考虑对于每个 x x x,我们倒着将 n n n个矩形插入,用并查集维护已经有颜色的集合,让后遍历,合并即可。
复杂度 O ( n 2 α ) O(n^2\alpha) O(n2α)
#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;
const int N=1000010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;
int n;
vector<int>ax,ay;
struct Mat {
int x1,y1,x2,y2,c;
}p[N];
struct DSU {
vector<int>p,se;
DSU(int n) : p(n), se(n, 1) { std::iota(p.begin(), p.end(), 0); }
int find(int x) {
return x==p[x]? x:p[x]=find(p[x]);
}
bool merge(int x,int y) {
int px=find(x),py=find(y);
if(px==py) return false;
p[px]=py;
se[py]+=se[px];
return true;
}
int size(int u) {
return se[find(u)];
}
};
int find(vector<int>v,int x) {
return lower_bound(v.begin(),v.end(),x)-v.begin();
}
void solve() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x1,y1,x2,y2,c;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
p[i]={x1,y2,x2,y1,c};
ax.push_back(x1);
ax.push_back(x2);
ay.push_back(y1);
ay.push_back(y2);
}
sort(ax.begin(),ax.end()); ax.erase(unique(ax.begin(),ax.end()),ax.end());
sort(ay.begin(),ay.end()); ay.erase(unique(ay.begin(),ay.end()),ay.end());
for(int i=1;i<=n;i++) {
int x1=find(ax,p[i].x1),y1=find(ay,p[i].y1);
int x2=find(ax,p[i].x2),y2=find(ay,p[i].y2);
p[i]={x1,y1,x2,y2,p[i].c};
}
vector<int>st(n+1,0);
for(int i=0;i<ax.size();i++) {
DSU dsu(ax.size()*2+1);
for(int j=n;j>=1;j--) {
int x1=p[j].x1,y1=p[j].y1;
int x2=p[j].x2,y2=p[j].y2;
if(x1<=i&&i<x2) {
for(int k=dsu.find(y1);k<y2;k=dsu.find(k)) {
dsu.merge(k,k+1);
st[p[j].c]=1;
}
}
}
}
cout<<count(st.begin(),st.end(),1)<<endl;
}
int main() {
int _=1;
while(_--) {
solve();
}
return 0;
}