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;
    }
    
  • 相关阅读:
    模型
    smarty变量
    smarty变量调节器
    分页
    表单验证(注册)
    php数据库访问
    php面向对象 继承
    php 面向对象
    php正则数组
    php 函数
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/9443501.html
Copyright © 2011-2022 走看看