P10237 [yLCPC2024] E. Latent Kindom 题解

文章讲述了如何使用二分查找和排序算法解决LatentKingdom问题,涉及合并两个有序序列并找到特定位置元素的过程,同时提到插入标兵优化二分搜索,时间复杂度为O(n+q)logl。

P10237 [yLCPC2024] E. Latent Kindom 题解

简单的单 log⁡\loglog 做法,不用会任何的数据结构就可以看懂。

解法

考虑把每个序列 aia_iai 升序排序,这样方便我们二分。

考虑将两个序列 ax,aya_x,a_yax,ay 合并,即选出在这两个序列中排名为 ⌈lenx+leny2⌉\lceil \dfrac{len_x+len_y}{2} \rceil2lenx+leny 的数,我们把合并后的序列分为两部分,一部分是小于等于中位数的,一部分是大于中位数的。我们发现小于等于中位数的那部分在 axa_xaxaya_yay 里是连续分布的,故我们考虑二分小于等于中位数的那部分在 axa_xax 中的分布情况。如图,该部分分布情况即为两个竖线左侧的连续区间。

图

当前 midmidmid 合法当且仅当 ax,mida_{x,mid}ax,miday,⌈len2⌉−mida_{y,\lceil \frac{len}{2} \rceil -mid}ay,2lenmid 都小于等于红色圈起来的两个数(即黑色竖线右侧的两个数)。

考虑如何移动二分的 l,rl,rl,r。当上面的黑色竖线比下面的红色圈大时,我们要把上面的黑色竖线向左移动,下面的黑色竖线向右移动;否则我们就把下面的黑色竖线向左移动,上面的黑色竖线向右移动,直到当前 midmidmid 合法。

复杂度分析:排序复杂度 O(nlog⁡l)\mathcal{O}(n \log l)O(nlogl),查询复杂度 O(qlog⁡l)\mathcal{O}(q \log l)O(qlogl),所以总复杂度 O((n+q)log⁡l)\mathcal{O}((n+q) \log l)O((n+q)logl)

在排序时这里有个小 trick,就是在 aia_iai 的前后放置两个标兵,一个极小值,一个极大值,防二分时越界。

代码

#include<bits/stdc++.h>
namespace fast_IO
{
	/**
	 * 快读快写
	*/
};
using namespace fast_IO;
#define int long long
int t,n,q,len[1000010];
std::vector<int> v[1000010];
inline int check(int x,int y,int lx,int ly)
{
	int midi=std::max(v[x][lx],v[y][ly]);
	if(midi<=v[x][lx+1] && midi<=v[y][ly+1]) return 1;
	if(midi>v[x][lx+1]) return 0;
	return 2;
}
signed main()
{
	in>>t;
	while(t--)
	{
		in>>n>>q;
		for(int i=1,x;i<=n;i++)
		{
			in>>len[i],v[i].clear(),v[i].push_back(-1),v[i].push_back(0x7fffffffffffffff);
			for(int j=1;j<=len[i];j++) in>>x,v[i].push_back(x);
			std::sort(v[i].begin(),v[i].end());
		}
		for(int i=1,tlen,x,y,l,r,mid,ret,ans;i<=q;i++)
		{
			in>>x>>y,tlen=len[x]+len[y],tlen=ceil(tlen/2.0);
			l=std::max(0ll,tlen-len[y]),r=std::min(len[x],tlen);
			while(l<=r)
			{
				mid=(l+r)/2,ret=check(x,y,mid,tlen-mid);
				if(ret==1)
				{
					ans=std::max(v[x][mid],v[y][tlen-mid]);
					break;
				}else if(ret==0) l=mid+1;
				else r=mid-1;
			}
			out<<ans<<'\n';
		}
	}
	fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值