zoukankan      html  css  js  c++  java
  • 【ARC069F】Flags

    Description

      
      数轴上有 (n)个旗子,第(i)个可以插在坐标(x_i)或者(y_i)
      
    ​   请最大化两两旗子之间的最小距离。
      
      ​ (2 le n le 10^4)(1 le x_i,y_i le 10^9)
      
      
      
      
      

    Solution

      
    ​   这种有若干组决策,每种决策二选一,然后要求所有决策互相合法的问题,习惯性的要往2-sat想一想。
      
    ​   我们把每个旗子(i)插在(x_i)还是(y_i)看做一种决策,分别用两个点表示。
      
    ​   看起来二分答案比较靠谱。
      
    ​   问题转变为:判定是否存在一种方案,使得两两旗子之间的最小距离不小于(len)
      
    ​   有了(x),我们就很方便地进行逻辑连边了。
      
    ​   考虑每个旗子(i)的两个位置。如果该旗子选择了(x_i),则对于所有处于((x_i-len,x_i+len))的位置(除了(x_i)),它们对应的旗子在决策时必须选择另一个可选位置,它们必须选择另外一个可选位置(p)。因此,从(x)向所有的(p)连一条边。
      
    ​   如果该旗子选择了(y_i)同理。
      
    ​   之后进行2-sat,即用Tarjan缩点。如果一个旗子的两个位置处于同一个强联通分量,则无解。否则一定可以构造出一种方案,由于这是一个判定问题,我们不需要真正构造。
      
    ​   由于点数较大无法(mathcal O(n^2))连边,我们使用线段树进行连边优化。
      
    ​   总时间复杂度为(mathcal O(n log_2 n log_2 1e9))
      

    Code

      

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <unordered_map>
    #define pb push_back
    using namespace std;
    const int N=10005,NUM=N*6;
    int n,p[N][2];
    int dcnt,d[N*2];
    unordered_map<int,int> tid;
    int lis[N*2];
    int nn;
    int dfntm,dfn[NUM],low[NUM],sta[NUM],top,bl[NUM],blcnt;
    bool ins[NUM];
    int h[NUM],tot;
    struct Edge{int v,next;}e[N*100];
    inline void addEdge(int u,int v){
    	//printf("%d %d
    ",u,v);
    	e[++tot]=(Edge){v,h[u]}; h[u]=tot;
    }
    void readData(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d%d",&p[i][0],&p[i][1]);
    }
    void Diz(){
    	for(int i=1;i<=n;i++) 
    		d[++dcnt]=p[i][0], d[++dcnt]=p[i][1];
    	sort(d+1,d+1+dcnt);
    	for(int i=1;i<=dcnt;i++)
    		if(d[i]!=d[i-1]) tid[d[i]]=i;
    	for(int i=1;i<=n;i++){
    		int x=p[i][0];
    		p[i][0]=tid[p[i][0]];
    		tid[x]++;
    		x=p[i][1];
    		p[i][1]=tid[p[i][1]];
    		tid[x]++;
    		lis[p[i][0]]=n+i;
    		lis[p[i][1]]=i;
    	}
    }
    namespace SEG{
    	const int S=N*4;
    	int rt,sz;
    	int ch[S][2];	
    	void reset(){
    		rt=sz=0;
    	}
    	void build(int &u,int l,int r){
    		if(l==r){
    			u=lis[l];
    			return;
    		}
    		u=++sz;
    		int mid=(l+r)>>1;
    		build(ch[u][0],l,mid);
    		build(ch[u][1],mid+1,r);
    		addEdge(u,ch[u][0]);
    		addEdge(u,ch[u][1]);
    	}
    	void link(int u,int l,int r,int L,int R,int v){
    		if(L<=l&&r<=R){
    			addEdge(v,u);
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(R<=mid) link(ch[u][0],l,mid,L,R,v);
    		else if(mid<L) link(ch[u][1],mid+1,r,L,R,v);
    		else{
    			link(ch[u][0],l,mid,L,mid,v);
    			link(ch[u][1],mid+1,r,mid+1,R,v);
    		}
    	}
    }
    void reset(){//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    	tot=0;
    	dfntm=blcnt=0; top=0;
    	for(int i=1;i<=nn;i++){
    		h[i]=0;
    		dfn[i]=low[i]=bl[i]=0;
    	}
    	SEG::reset();
    }
    void tarjan(int u){/*{{{*/
    	dfn[u]=low[u]=++dfntm;
    	sta[++top]=u;
    	ins[u]=true;
    	for(int i=h[u],v;i;i=e[i].next){
    		v=e[i].v;
    		if(!dfn[v]){
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(ins[v])
    			low[u]=min(low[u],dfn[v]);
    	}
    	if(dfn[u]==low[u]){
    		blcnt++;
    		int x;
    		do{
    			x=sta[top];
    			sta[top--]=0;
    			ins[x]=false;
    			bl[x]=blcnt;
    		}while(x!=u);
    	}
    }/*}}}*/
    bool judge(int x){
    	reset();
    	SEG::sz=n*2;
    	SEG::build(SEG::rt,1,dcnt);
    	for(int i=1;i<=n;i++){
    		int l=lower_bound(d+1,d+1+dcnt,d[p[i][0]]-x+1)-d;
    		int r=upper_bound(d+1,d+1+dcnt,d[p[i][0]]+x-1)-d-1;
    		if(l<=r){
    			if(l<p[i][0]) 
    				SEG::link(SEG::rt,1,dcnt,l,p[i][0]-1,i);
    			if(p[i][0]<r)
    				SEG::link(SEG::rt,1,dcnt,p[i][0]+1,r,i);
    		}
    		l=lower_bound(d+1,d+1+dcnt,d[p[i][1]]-x+1)-d;
    		r=upper_bound(d+1,d+1+dcnt,d[p[i][1]]+x-1)-d-1;
    		if(l<=r){
    			if(l<p[i][1]) 
    				SEG::link(SEG::rt,1,dcnt,l,p[i][1]-1,n+i);
    			if(p[i][1]<r)
    				SEG::link(SEG::rt,1,dcnt,p[i][1]+1,r,n+i);
    		}
    	}
    	nn=SEG::sz;
    	for(int i=1;i<=nn;i++)
    		if(!dfn[i])
    			tarjan(i);
    	for(int i=1;i<=n;i++)
    		if(bl[i]==bl[n+i]) return false;
    	return true;
    }
    void solve(){
    	int l=0,r=1e9,mid;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(judge(mid)) 
    			l=mid+1;
    		else r=mid-1;
    	}
    	printf("%d
    ",r);	
    }
    int main(){
    	readData();
    	Diz();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    Running ASP.NET Applications in Debian and Ubuntu using XSP and Mono
    .net extjs 封装
    ext direct spring
    install ubuntu tweak on ubuntu lts 10.04,this software is created by zhouding
    redis cookbook
    aptana eclipse plugin install on sts
    ubuntu open folderpath on terminal
    ubuntu install pae for the 32bit system 4g limited issue
    EXT Designer 正式版延长使用脚本
    用 Vagrant 快速建立開發環境
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/9443501.html
Copyright © 2011-2022 走看看