题目
解法
一般这种矩形题都会想到扫描线,所以讲讲线段树维护。
如果非常直接地求解区间内显示的不同颜色数是做不动的,因为这个没法用线段树合并信息。
考虑设 maxx[i]
为 (i) 号节点代表区间中 未 被统计的能看到的最大颜色。这样我们可以对于每一个 (x),先将其对应的矩形的颜色改在线段树上,算出 maxx[root]
,若不为 (0) 就 ++ans
,然后去掉那个矩形。除此之外还需要维护 minn[i]
为完全覆盖节点 (i) 的区间的颜色至少为多少能被看到。
这给我们一个启示:可以将种类数分解成一步步的最值处理(感觉我在讲废话)。
代码
#include <cstdio>
#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
#include <map>
#include <set>
#include <vector>
using namespace std;
const int maxn=1e5+5;
int n,maxx[maxn<<3],minn[maxn<<3];
bool vis[maxn];
map <int,int> X,Y;
set <int> st[maxn<<3];
map <int,int> :: iterator it;
struct dots {int a,b,c,d;} D[maxn];
struct node {int l,r,val;};
vector <node> sq[maxn<<1];
void pushUp(int o,bool op) {
if(op) maxx[o]=minn[o]=0;
else maxx[o]=Max(maxx[o<<1],maxx[o<<1|1]),minn[o]=Min(minn[o<<1],minn[o<<1|1]);
if(!st[o].empty()) {
int val=*st[o].rbegin();
if(vis[val]) minn[o]=Max(minn[o],val);
else maxx[o]=Max(maxx[o],val);
}
if(minn[o]>maxx[o]) maxx[o]=0;
}
void modify(int o,int l,int r,int L,int R,int val) {
if(l>R || r<L) return;
if(l>=L && r<=R) {
// 注意这是完全包含
if(val>0) st[o].insert(val);
else st[o].erase(-val);
pushUp(o,l==r);
return;
}
int mid=l+r>>1;
modify(o<<1,l,mid,L,R,val),modify(o<<1|1,mid+1,r,L,R,val);
pushUp(o,0);
}
int main() {
n=read(9);
rep(i,1,n) {
D[i].a=read(9),D[i].b=read(9),D[i].c=read(9),D[i].d=read(9);
X[D[i].a]=X[D[i].c]=1;
Y[D[i].b]=Y[D[i].d]=1;
}
int cntx=0,cnty=0,ans=1;
for(it=X.begin();it!=X.end();++it) it->second=++cntx;
for(it=Y.begin();it!=Y.end();++it) it->second=++cnty;
rep(i,1,n) {
D[i].a=X[D[i].a],D[i].b=Y[D[i].b],D[i].c=X[D[i].c],D[i].d=Y[D[i].d]-1;
// 由于题目给的是点的坐标,计算的是一个方格,所以 b 不用 +1,d 要 -1。这也是区间长度为 0 赋值为 0 的原因
sq[D[i].a].push_back((node){D[i].b,D[i].d,i}),sq[D[i].c].push_back((node){D[i].b,D[i].d,-i});
}
rep(i,1,cntx) {
for(int j=0;j<sq[i].size();++j) modify(1,1,cnty,sq[i][j].l,sq[i][j].r,sq[i][j].val);
while(maxx[1]) {
vis[maxx[1]]=1; ++ans;
modify(1,1,cnty,D[maxx[1]].b,D[maxx[1]].d,0);
}
}
print(ans,'
');
return 0;
}