[ARC069F] Flags 题解

主要讲解线段树优化建图。


正常建图的话复杂度是平方级的,加上二分答案的复杂度直接炸。

观察到我们建图时每一个位置连边的其他位置都是一个区间,所以我们考虑线段树优化建图。核心思想是:像线段树一样的构型的连边以减少连边数量。

首先先将每个位置点排序。

方法是,构造线段树时,将每一个父亲向自己的每个儿子连边直到 \(l=r\) 时,此时将叶子向自己的相对位置(如 \(x_1\)\(y_1\) 相对)连一个边。

接下来你只需要把当前需要连边的节点与自己需要连向的范围在线段树上进行连边即可。


#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x7fffffff
const ll maxn=3e5+10;
ll low[maxn],dfn[maxn],vis[maxn];
ll tot,cnt,color[maxn],n;
pair<ll,ll> node[maxn];
stack<ll> q;
vector<ll> G[maxn];
struct tree{ll l,r,id;}t[maxn];
inline void solve(ll u) {
	q.pop();
	vis[u]=0;color[u]=tot;
}
inline void tarjan(ll u) {
	dfn[u]=low[u]=vis[u]=++cnt;
	q.push(u);
	for (ll i=0;i<G[u].size();++i) {
		ll v=G[u][i];
		if (!dfn[v]) {
			tarjan(v);
			low[u]=min(low[v],low[u]);
		}
		else if (vis[v]) low[u]=min(low[u],dfn[v]);
	}
	if (low[u]==dfn[u]) {
		tot++;
		while (q.top()!=u) solve(q.top());
		solve(u);
	}
}
ll cntt;
inline ll opposite(ll x) {
	if (x<=n) return x+n;
	else return x-n;
}
inline void init() {
	while (!q.empty()) q.pop();
	for (ll i=1;i<=cntt;++i) low[i]=dfn[i]=vis[i]=color[i]=0;
	for (ll i=1;i<=cntt;++i) G[i].clear(); 
	tot=cnt=0;cntt=2*n;
}
inline void build(ll p,ll l,ll r) {
	t[p].id=++cntt;t[p].l=l;t[p].r=r;
//	cout<<p<<" "<<t[p].l<<" "<<t[p].r<<" "<<endl;
	if (l==r) {
		G[t[p].id].push_back(opposite(node[l].second));
		return;
	}
	ll mid=(l+r)>>1;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
	G[t[p].id].push_back(t[p<<1].id);
	G[t[p].id].push_back(t[p<<1|1].id);
	
}
inline void link(ll p,ll l,ll r,ll x) {
//	cout<<p<<" "<<t[p].l<<" "<<t[p].r<<" "<<l<<" "<<r<<endl;
	if (l>r) return;
	if (t[p].l>=l&&t[p].r<=r) {
		G[x].push_back(t[p].id);
		return;
	}
	ll mid=(t[p].l+t[p].r)>>1;
	if (l<=mid) link(p<<1,l,r,x);
	if (r>mid) link(p<<1|1,l,r,x);
}
inline bool check(ll x) {
	init();
	build(1,1,2*n);
	for (ll i=1;i<=2*n;++i) {
		ll inff=inf;
		ll l=upper_bound(node+1,node+1+n*2,make_pair(node[i].first-x,inff))-node;
		ll r=upper_bound(node+1,node+1+2*n,make_pair(node[i].first+x-1,inff))-node-1;
		link(1,l,i-1,node[i].second);link(1,i+1,r,node[i].second);
	}
	for (ll i=1;i<=2*n;++i) if (!dfn[i]) tarjan(i);
	for (ll i=1;i<=n;++i) if (color[i]==color[i+n]) return false;
	return true;
}
inline ll in() {
    char a=getchar();
	ll t=0,f=1;
	while(a<'0'||a>'9') {if (a=='-') f=-1;a=getchar();}
    while(a>='0'&&a<='9') {t=(t<<1)+(t<<3)+a-'0';a=getchar();}
    return t*f;
}
signed main() {
	n=in();
	for (ll i=1;i<=n;++i) {
		node[i].first=in(),node[i+n].first=in();
		node[i].second=i;node[i+n].second=i+n;
	}
	sort(node+1,node+1+2*n);
	ll l=0,r=node[n*2].first-node[1].first+1,mid;
	while (l<r) {
		mid=(l+r+1)>>1;
		if (check(mid)) l=mid;
		else r=mid-1;
	}
	printf("%lld",l);
	return 0;
}
posted @ 2023-09-18 20:07  Pwtking  阅读(25)  评论(0)    收藏  举报