zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    算法-最大公约数
    算法-最大连续子序列和
    iOS开发-Bug锦囊
    iOS开发-简单抽奖
    iOS开发-UIActionSheet简单介绍
    iOS开发-UIActivityIndicatorView简单使用
    iOS开发-UITextView实现PlaceHolder的方式
    iOS开发-Reachability实时检测Wifi,2G/3G/4G/网络状态
    [转]jsPlumb插件做一个模仿viso的可拖拉流程图
    Python 日期和时间
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14449252.html
Copyright © 2011-2022 走看看