[CF1498E]Two Houses

本文阐述了在一个竞赛图中,入度较大节点到入度较小节点存在路径的性质,并提供了证明。核心在于利用入度差和双联通结构,通过O(n^2 log n)的时间复杂度找到关键点对。博主展示了如何通过代码实现这一算法并举例说明。
摘要由CSDN通过智能技术生成

Two Houses

题解

首先,我们可以证明,在一个竞赛图中,若入度较大的点有一条路径能够到入度较小的点,那么入度较小的点也必然有一条路径能够到入度较大的点。

证明如下:
我们令点 i i i的入集为 U i U_{i} Ui,出集为 V i V_{i} Vi,点 x , y x,y x,y ∣ U x ∣ ⩽ ∣ U y ∣ |U_{x}|\leqslant|U_{y}| UxUy,且 y y y有一条能够到 x x x的路径。
y y y没有直接到 x x x的边,那么 x x x肯定有一条直接到 y y y的边,它们间肯定是双联通。
y y y有直接到 x x x的边,那么 x ∈ V y , y ∈ U x x\in V_{y},y\in U_{x} xVy,yUx。由于 U x ⋂ V x = ∅ , U x ⋃ V x = I − { x } U_{x}\bigcap V_{x}=\empty,U_{x}\bigcup V_{x}=I-\{x\} UxVx=,UxVx=I{x},所以 ∣ V x ∣ = n − 1 − ∣ U x ∣ |V_{x}|=n-1-|U_{x}| Vx=n1Ux
由于 ∣ U y ∣ ⩾ ∣ U x ∣ |U_{y}|\geqslant |U_{x}| UyUx,且 U y U_{y} Uy不包含 x , y x,y x,y,所以 U y ⋂ V x ≠ ∅ U_{y}\bigcap V_{x}\not=\empty UyVx=
所以必然存在一个 x x x能到的点拥有一条到 y y y的边。
所以,如果 y y y有一条能到 x x x的路径,那么 x x x必然能到 y y y
zengbi

所以,我们只需要把所有的点对找出来,按入度差的大小排序,枚举最大的双联通的点对即可。

时间复杂度 O ( n 2 log ⁡   n ) O\left(n^2\log\,n\right) O(n2logn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mp make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x7f7f7f7f;
const int jzm=233;
const int mo=1e9+7;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,tot;char str[10];
struct ming{int k,id;}s[MAXN];
struct node{int u,v,w;}e[MAXN];
bool cmp(ming x,ming y){return x.k<y.k;}
bool cmp1(node x,node y){return x.w>y.w;}
bool Ask(int u,int v){
	printf("? %d %d\n",u,v);fflush(stdout);
	scanf("\n%s",str+1);return str[1]=='Y';
}
signed main(){
	read(n);for(int i=1;i<=n;i++)read(s[i].k),s[i].id=i;
	sort(s+1,s+n+1,cmp);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			e[++tot]=(node){s[j].id,s[i].id,s[j].k-s[i].k};
	sort(e+1,e+tot+1,cmp1);
	for(int i=1;i<=tot;i++)
		if(Ask(e[i].u,e[i].v)){printf("! %d %d\n",e[i].u,e[i].v);return 0;}
	puts("! 0 0");
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值