首页 > 其他分享 >[ARC069F]Flags 题解

[ARC069F]Flags 题解

时间:2022-11-06 12:23:45浏览次数:98  
标签:fir le int 题解 mid ARC069F sec Flags 反点

因为一个小错误整整调了一天 qwq

除去 2-SAT 部分没学过去学了一下,其它部分都想出来了,四舍五入我自己写了一道 Cu,好欸(虽然这 Cu 好像非常水QAQ)。

F - Flags

一条数轴上有 \(n\) 个旗帜,第 \(i\) 个旗的位置可能是 \(x_i\) 或 \(y_i\),最大化旗帜间两两距离的最小值。

\(1\le n\le 10^4,1\le x_i,y_i\le 10^9\)

最大化最小值,直接二分答案,设当前二分到的值为 \(d\)。

为了方便,我们称 \(x_i\) 和 \(y_i\) 互为「反点」。

将所有 \(x_i,y_i\) 在数轴上升序排序,考虑取了一个点 \(x\),则 \((x-d,x+d)\) 之间的点都取不了,也就是说,我们只能取 \(x\) 或 \((x-d,x+d)\) 中的点这两种之一。换言之,如果取了 \(x\),就只能取 \((x-d,x+d)\) 中的点的「反点」。

这个是 2-SAT 问题的经典模型,我们将 \(x\) 和这些「反点」连有向边,跑 Tarjan 算 SCC,如果互为「反点」的两个点在同一个 SCC 中,则判定无解,反之有解,构造方法珂以去 2-SAT 的模板题题解里学,因为此题仅需判定,此处略过。

此时还有一个问题:如果暴力连边的话边数会非常非常多,时间和空间可能扛不住。

这题 5s 1GB 时空?直接暴力莽!(

我们要用到一个叫线段树优化建图的 Trick,模板见 [CF786B]Legacy,而且此题只需要由单点向区间连边,那么只需要建出一棵线段树,父节点向子节点连边即可。

总时间复杂度 \(\mathcal O(n\log n\log x_i)\)

Code

// Problem: [ARC069F] Flags
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_arc069_d
// Memory Limit: 256 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define fir first
#define sec second
#define pb emplace_back
using pii = std::pair<int,int>;

const int maxn = 2e4 + 5;
int n,a[maxn][2];
std::vector<pii> s;
std::vector<int> G[maxn << 2];
int ls[maxn << 2],rs[maxn << 2],id[maxn << 2],num;

void build(int i,int l,int r) {
	ls[i] = l;
	rs[i] = r;
	num = std::max(num , i);
	if(l == r) {
		id[s[l - 1].fir + (!s[l - 1].sec) * n] = i;
		return ;
	}
	int mid = l + r >> 1;
	build(i << 1 , l , mid);
	build(i << 1 | 1 , mid + 1 , r);
	G[i].pb(i << 1);
	G[i].pb(i << 1 | 1);
	return ;
}

void connect(int i,int l,int r,int pos) {
	if(ls[i] >= l&&rs[i] <= r) {
		G[pos].pb(i);
		return ;
	}
	if(ls[i] > r||rs[i] < l)return ;
	int mid = ls[i] + rs[i] >> 1;
	if(l <= mid)connect(i << 1 , l , r , pos);
	if(r > mid)connect(i << 1 | 1 , l , r , pos);
	return ;
}

int cnt,low[maxn << 2],dfn[maxn << 2],stk[maxn << 2],tp,col[maxn << 2],tot;
bool ins[maxn << 2];

void init() {
	for(int i = 1;i <= num;++ i)
		G[i].clear();
	tp = cnt = tot = num = 0;
	memset(low , 0 , sizeof(low));
	memset(dfn , 0 , sizeof(dfn));
	memset(col , 0 , sizeof(col));
	memset(ins , false , sizeof(ins));
	memset(ls , 0 , sizeof(ls));
	memset(rs , 0 , sizeof(rs));
	memset(id , 0 , sizeof(id));
	return ;
}

void tarjan(int u) {
	low[u] = dfn[u] = ++ cnt;
	stk[++ tp] = u;
	ins[u] = true;
	for(auto& v : G[u]) {
		if(!dfn[v])
			tarjan(v),low[u] = std::min(low[u] , low[v]);
		else if(ins[v])
			low[u] = std::min(low[u] , dfn[v]);
	}
	if(dfn[u] == low[u]) {
		++ tot;
		do {
			ins[stk[tp]] = false;
			col[stk[tp]] = tot;
		} while(tp&&stk[tp --] != u);
	}
	return ;
}

bool check(int d) {
	init();
	build(1 , 1 , (int)s.size());
	for(int i = 1,l = 1,r = 1;i <= (int)s.size();++ i) {
		while(l < i&&a[s[i - 1].fir][s[i - 1].sec] - a[s[l - 1].fir][s[l - 1].sec] >= d)
			++ l;
		while(r < (int)s.size()&&a[s[r].fir][s[r].sec] - a[s[i - 1].fir][s[i - 1].sec] < d)
			++ r;
		if(l < i)connect(1 , l , i - 1 , id[s[i - 1].fir + s[i - 1].sec * n]);
		if(i < r)connect(1 , i + 1 , r , id[s[i - 1].fir + s[i - 1].sec * n]);
	}
	for(int i = 1;i <= num;++ i)
		if(!dfn[i])tarjan(i);
	for(int i = 1;i <= n;++ i) {
		if(col[id[i]] == col[id[i + n]])
			return false;
	}
	return true;
}

int main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;++ i)
		scanf("%d %d",&a[i][0],&a[i][1]),s.pb(i , 0),s.pb(i , 1);
	std::sort(s.begin() , s.end() , [&](const pii& p,const pii& q) {
		return a[p.fir][p.sec] < a[q.fir][q.sec];
	});
	
	int l = 0,r = 1e9;
	while(l <= r) {
		int mid = l + r >> 1;
		if(check(mid))l = mid + 1;
		else r = mid - 1;
	}
	
	printf("%d\n",r);
	return 0;
}

标签:fir,le,int,题解,mid,ARC069F,sec,Flags,反点
From: https://www.cnblogs.com/Royaka/p/16862370.html

相关文章

  • P8813(CSP-J2022T1)题解
    题意:算a ^ b,如果结果超出1e9就输出-1,反之输出结果。思路:边算边判加特判。代码:#include<cstdio>#definelllonglong#definemx1e9//边界usingnamespacestd;i......
  • P8814(CSP-J2022T2)题解
    题意:给定一个正整数 k,有k 次询问,每次给定三个正整数 n, e, d,求两个正整数 p, q,使 n = p × q且e × d =(p −1)×(q −1)+1。思路:通过题意可以发......
  • AtCoder Beginner Contest 276 A~G 题解
    今天凌晨CFD题差一句判断AC,晚上ABCG题把插板法和快速幂搞混差点AC。事不过三,再这样一次我直接紫砂。太简单的题就不放翻译和代码了。(事实上这场A-E都是大水题......
  • 个人比赛实况和题解
    CodeforcesCF1740:实况:https://pan.baidu.com/s/1BYjUp2Atvqkpqe3jVogPTQ(提取码:1104);题解:https://www.cnblogs.com/lucius7/p/16861747.html。AtCoderabc275:实况:https://p......
  • 洛谷P8757 [蓝桥杯 2021 省 A2] 完美序列 题解
    思路为使描述方便,先令题目描述中的“完美序列”反转(即序列单调递增且每一个数都是上一个数的倍数)。原“完美序列”与反转后的本质相同。先考虑最大长度。显然,当完美序列......
  • 洛谷P8775 [蓝桥杯 2022 省 A] 青蛙过河 题解 贪心+二分答案
    题目链接​​https://www.luogu.com.cn/problem/P8775​​题目大意小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。河里的石头排成了一条......
  • 洛谷-P8814 题解
    前言蒟蒻感叹!许多大佬的思路真的很复杂,于是为了部分没学过的人写了这篇题解(其实就是为了咕值),值得一看!正文♦算法:式子推导从题中可得\(\begin{cases}n_i=p_i\times......
  • 「题解报告」[POI2008]PER-Permutation
    「题解报告」[POI2008]PER-Permutation点击查看目录目录「题解报告」[POI2008]PER-Permutation思路代码不理解哪里难了,学过扩卢并且推一下式子基本就是两眼切吧。......
  • Luogu P5816[CQOI2010]内部白点题解
    LinkLuoguP5816Description一个平面直角坐标系内有\(n\)个黑点,其余点为白点,将会进行若干次变换,每次变换会把上下左右方向都有黑点的白点变成黑点,直到找不到符合要求......
  • python print 打印延迟问题解决
    转载:https://wenku.baidu.com/view/ffc89347bb4ae45c3b3567ec102de2bd9705de56.html?wkts=1667639107060&bdQuery=python+print%E7%AB%8B%E5%8D%B3%E6%89%93%E5%8D%B0......