zoukankan      html  css  js  c++  java
  • AT2336 [ARC069D] Flags 2-SAT 线段树优化建图

    题意:

    戳这里

    分析:

    挺裸的一道题,直接二分答案,然后建图跑 (2-SAT) 判断合法性

    但是会发现复杂度瓶颈在于 (O(n^2)) 建图

    我们发现每一次连边都是向距离在 ((min,pos_i-mid))((pos_i+mid,max)) 这段区间内的点连边,然后我们就可以用线段树优化建图来将建图的复杂度降低到 (O(nlog ))

    tip:

    1. 按照 (pos) 为关键字对点进行升序排序,建图的时候,每个叶子结点向自己的对应点连一条边,这样连边方式变成了向一段区间内连边,但是一定要少掉自己,即向 ((pos_i-mid,pos_i))((pos_i+1,pos_i+mid)) 区间连边
    2. 由于每次 (check) 会清空 (head) 数组,所以会将建出来的线段树也清掉,所以每次记得重建一次

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 2e5+5;
    	int n,m,top,col,tim,idx,cnt;
    	int id[maxn],head[maxn],bel[maxn],dfn[maxn],low[maxn],st[maxn];
    	bool vis[maxn];
    	
    	struct edge
    	{
    		int to,nxt;
    	}e[maxn<<3];
    	
    	void add(int u,int v)
    	{
    		e[++cnt].to=v;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	struct node
    	{
    		int pos,id;
    		node(){}
    		node(int pos,int id=0):pos(pos),id(id){}
    		bool operator <(const node &b)const
    		{
    			return pos<b.pos;
    		}
    	}p[maxn];
    	
    	int op(int x)
    	{
    		return x<=n?x+n:x-n;
    	}
    	
    	void build(int rt,int l,int r)
    	{
    		id[rt]=++idx;
    		if(l==r)
    		{
    			add(id[rt],op(p[l].id));
    			return ;
    		}
    		int mid=(l+r)>>1;
    		build(lc,l,mid);build(rc,mid+1,r);
    		add(id[rt],id[lc]);add(id[rt],id[rc]);
    	}
    	
    	void link(int rt,int l,int r,int ql,int qr,int x)
    	{
    		if(ql>qr) return ;
    		if(ql<=l&&r<=qr)
    		{
    			add(x,id[rt]);
    			return ;
    		}
    		int mid=(l+r)>>1;
    		if(ql<=mid) link(lc,l,mid,ql,qr,x);
    		if(qr>mid) link(rc,mid+1,r,ql,qr,x);
    	}
    	
    	void tarjan(int u)
    	{
    		dfn[u]=low[u]=++tim;
    		st[++top]=u;
    		vis[u]=true;
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(!dfn[v])
    			{
    				tarjan(v);
    				low[u]=min(low[u],low[v]);
    			}
    			else if(vis[v]) low[u]=min(low[u],dfn[v]);
    		}
    		if(low[u]==dfn[u])
    		{
    			col++;
    			do
    			{
    				bel[st[top]]=col;
    				vis[st[top]]=false;
    			}while(st[top--]!=u);
    		}
    	}
    	
    	bool check(int x)
    	{
    		for(int i=1;i<=idx;i++) head[i]=0,dfn[i]=0;
    		cnt=0;tim=0;top=0;
    		build(1,1,idx=2*n);
    		for(int i=1;i<=2*n;i++)
    		{
    			int l=upper_bound(p+1,p+2*n+1,node(p[i].pos-x))-p;
    			int r=upper_bound(p+1,p+2*n+1,node(p[i].pos+x-1))-p-1;
    			link(1,1,2*n,l,i-1,p[i].id);link(1,1,2*n,i+1,r,p[i].id);
    		}
    		for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
    		for(int i=1;i<=n;i++) if(bel[i]==bel[i+n]) return false;
    		return true;
    	}
    	
    	void work()
    	{
    		n=read();
    		for(int i=1;i<=n;i++)
    		{
    			p[i].pos=read();p[i+n].pos=read();
    			p[i].id=i;p[i+n].id=i+n;
    		}
    		sort(p+1,p+2*n+1);
    		int l=0,r=p[2*n].pos-p[1].pos+1,mid,ans;
    		while(l<=r)
    		{
    			mid=(l+r)>>1;
    			if(check(mid))
    			{
    				ans=mid;
    				l=mid+1;
    			}
    			else r=mid-1;
    		}
    		printf("%d
    ",ans);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    mysql 的锁
    vsphere虚拟机连网
    三种响应式文字(废弃)
    学习笔记(六)
    优秀 H5 案例收集 vol.3(不定期更新)
    优秀 H5 案例收集 Vol.2(不定期更新)
    优秀 H5 案例收集 vol.1(不定期更新)
    手机调取摄像头问题(getUserMedia)
    ES6 随记(3.3)-- 数组的拓展
    input-file 部分手机不能拍照问题
  • 原文地址:https://www.cnblogs.com/youth518/p/14284913.html
Copyright © 2011-2022 走看看