文章目录
- 题意:
- 思路
传送门
题意:
给你平面nnn个矩形,每个矩形有一种颜色,依次给出矩形以及其的颜色,后面的矩形会覆盖前面的矩形,问最终有多少种颜色。
1≤n≤4000,0≤x1<x2<228,0≤y1<y2<228,1≤c≤n1\le n\le 4000,0\le x_1<x_2< 2^{28},0\le y_1<y_2< 2^{28},1\le c\le n1≤n≤4000,0≤x1<x2<228,0≤y1<y2<228,1≤c≤n
思路
首先第一个应该想到的就是倒着来,因为后面的会覆盖前面的。
其次由于坐标范围很大,不难想到离散化一下。
矩阵的问题,很容易往扫描线上靠,让后看一下nnn,显然可以想到n2lognn^2lognn2logn的算法。
矩形扫描线的第一步也是最重要的一步,就是将线段化点,因为矩形如果只存点的话,是显然不对的,比如第三个样例,如果只考虑点的话就会漏掉一种颜色。
让后就是暴力的考虑对于每个xxx,我们倒着将nnn个矩形插入,用并查集维护已经有颜色的集合,让后遍历,合并即可。
复杂度O(n2α)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;
}