zoukankan      html  css  js  c++  java
  • 「CEOI2019」建造摩天楼

    「CEOI2019」建造摩天楼

    显然是倒着考虑删除每个大楼,此时每次面临的情况都是一个子问题

    下文称当前局面未被删除的大楼为黑点,其余为白点

    子问题有解的充要条件是:黑点之间能 8-连通

    当前一个点能够被删掉的条件是:

    1.这个点能够连通到无穷处

    2.这个点不是当前8-连通图的割点

    [ ]

    考虑用一个简单的方法维护条件1:

    将一开始每个黑点周围的白点取出,按照白点之间4-连通构建连通块

    能够4-连通接触到最外层连通块的黑点满足条件1

    每次删除黑点之后,增加能够连通的白点,每个白点只会增加一次

    ps:寻找最外层4-连通白点的一个方法:找到x最大的白点

    [ ]

    接下来考虑如何判定一个点(u)是否是割点:

    首先删除(u)之后,周围8连通内能够构成多个连通块,可以发现大致可以归结为以下几种情况,其中x,y为黑点

    多个(x)表示(x)在其中任何一个位置都可以

    1.
    x y
    x u y
    x y
    2.
    x y
    u y
    y y y

    对于这两种情况,只要白点1和白点2在同一4-连通块,割掉(u)就会分开x和(y)

    由此,每次插入一个白点,可以(O(1))检测一个点是否合法

    简单讨论可以发现,会被影响合法性的点,一定在新加入最外层连通块的白点周围

    这样总共check了(O(n))次,每次用一个堆/set维护能选的最大编号的点即可

    ps:代码非常丑非常垃圾。。。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef pair <int,int> Pii;
    #define mp make_pair
    #define pb push_back
    #define x first
    #define y second
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    
    char IO;
    template <class T=int> T rd(){
    	T s=0; int f=0;
    	while(!isdigit(IO=getchar())) f|=IO=='-';
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int N=1.3e6+10,INF=1e9+10;
    const int z[5][4]={{1,0},{0,-1},{-1,0},{0,1}};
    const int Z[9][4]={{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1}};
    
    int n,m,k;
    int F[N];
    int Find(int x){ return F[x]==x?x:F[x]=Find(F[x]);}
    void Union(int x,int y){ F[Find(x)]=Find(y); }
    map <Pii,int> B,W;
    set <int> st;
    vector <int> ans;
    Pii A[N],P[N];
    int ma=-1e9,maxid;
    int G[N][4];
    void Ins(int x,int y){
        // Insert white point
    	Pii T=mp(x,y);
    	if(B.count(T)) return ;
    	if(!W.count(T)) P[W[T]=++m]=T,F[m]=m;
    	int u=W[T];
    	if(x>ma) ma=x,maxid=u;
    	rep(i,0,3) {
    		int x1=x+z[i][0],y1=y+z[i][1];
    		if(W.count(mp(x1,y1))) {
    			int v=W[mp(x1,y1)];
    			G[u][i]=v;
    			G[v][(i+2)%4]=u;
    			Union(u,v);
    		}
    	}
    }
    
    int del[N],vis[N],reach[N];
    int Check(int u){
    	if(del[u]||!reach[u]) return 0;
    	static int I[8];
    	int c=0;
    	rep(i,0,7) {
    		Pii T=mp(A[u].x+Z[i][0],A[u].y+Z[i][1]);
    		if(W.count(T)) I[i]=Find(W[T]);
    		else I[i]=0,c++;
    	}
    	for(int i=1,t=0;t<4;t++,i=(i+2)%8){
    		int j=(i+2)%8;
    		if(I[i] && I[i]==I[j] && !I[(i+1)%8] && c>1) return 0;
    	}
    	if((!I[0]||!I[1]||!I[2]) && (!I[4]||!I[5]||!I[6]) && I[3] && I[3]==I[7]) return 0;
    	if((!I[2]||!I[3]||!I[4]) && (!I[6]||!I[7]||!I[0]) && I[1] && I[5]==I[1]) return 0;
    	return 1;
    }
    void ReCheck(int u){
    	auto it=st.find(u);
    	if(it!=st.end()) st.erase(it);
    	if(Check(u)) st.insert(u);
    }
    
    vector <int> tmp;
    void dfs(int u){
    	if(!u) return;
    	if(vis[u]) return;
    	vis[u]=1;
    	rep(i,0,3) {
    		if(G[u][i]) dfs(G[u][i]);
    		Pii T=mp(P[u].x+z[i][0],P[u].y+z[i][1]);
    		if(B.count(T)) reach[B[T]]=1;
    	}
    	rep(dx,-1,1) rep(dy,-1,1) if(dx||dy) {
    		Pii T=mp(P[u].x+dx,P[u].y+dy);
    		if(B.count(T)) tmp.pb(B[T]);
    	}
    }
    void Dfs(int u){
    	dfs(u);
    	sort(tmp.begin(),tmp.end()),tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
    	for(int i:tmp) ReCheck(i);
    	tmp.clear();
    }
    
    void Del(int u){
        // delete black point
    	del[u]=1;
    	B.erase(A[u]),Ins(A[u].x,A[u].y);
    	Dfs(W[A[u]]);
    }
    
    int main(){
    	n=rd(),rd();
    	rep(i,1,n) A[i].x=rd(),A[i].y=rd(),B[A[i]]=i;
    	rep(i,1,n) F[i]=i;
    	
    	// Check NO
    	rep(i,1,n) { 
    		rep(dx,-1,1) rep(dy,-1,1) {
    			Pii T=mp(A[i].x+dx,A[i].y+dy);
    			if(B.count(T)) Union(i,B[T]);
    		}
    	}
    	rep(i,1,n) if(Find(i)!=Find(1)) return puts("NO"),0;
    
    	rep(i,1,n) rep(dx,-1,1) rep(dy,-1,1) if(dx||dy) Ins(A[i].x+dx,A[i].y+dy);
    	Dfs(maxid);
    
    	rep(i,1,n) {
    		int u=*st.rbegin();
    		auto it=st.end(); --it;st.erase(it);
    		Del(u),ans.pb(u);
    	}
    	reverse(ans.begin(),ans.end());
    	puts("YES");
    	for(int i:ans) printf("%d
    ",i);
    }
    
  • 相关阅读:
    MSSQL
    Dapper
    Asynchronous Programming
    PHP on CentOS (LAMP) and wordpress
    CSS
    TypeScript & JavaScript
    AngularJS 2.0
    ReadMe.md MarkDown file
    shortcuts on Windows and MacOS
    移动平台的meta标签
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14446391.html
Copyright © 2011-2022 走看看