CodeForces

题目

传送门

解法

一般这种矩形题都会想到扫描线,所以讲讲线段树维护。

如果非常直接地求解区间内显示的不同颜色数是做不动的,因为这个没法用线段树合并信息。

考虑设 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;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/14449252.html