专栏文章

P7561 [JOISC 2021] 道路の建設案 (Road Construction) (Day2) 题解

P7561题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miprr5na
此快照首次捕获于
2025/12/03 16:52
3 个月前
此快照最后确认于
2025/12/03 16:52
3 个月前
查看原文

前置知识

解法

观察到所求是一个邻域查询的形式,尝试使用 KD-Tree,但需注意最坏时间复杂度并不正确(因为本题数据稍弱所以可以通过)。
luogu P2093 [国家集训队] JZPFAR,不妨开一个大小为 2k2k 的堆加入答案时不断和堆顶比较,在输出答案时跳着取答案。
启发式搜索时估价函数取到子矩形的最近距离即可。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
const ll inf=0x7f7f7f7f7f7f7f7f;
struct node
{
	int pos[2];
}a[250010];
int cur,cnt=0;
ll ans[250010];
priority_queue<ll>q;
bool cmp(node x,node y)
{
	return x.pos[cur]<y.pos[cur];
}
ll get_dis(int x,int y)
{
	return llabs(a[x].pos[0]-a[y].pos[0])+llabs(a[x].pos[1]-a[y].pos[1]);
}
struct KDT
{
	int root;
	struct kd_tree
	{
		int ls,rs,pos[2],mx[2],mn[2];
	}tree[250010];
	#define lson(rt) (tree[rt].ls)
	#define rson(rt) (tree[rt].rs)
	int build_rt(int id)
	{
		int rt=id;
		lson(rt)=rson(rt)=0;
		for(int i=0;i<=1;i++)
			tree[rt].pos[i]=tree[rt].mx[i]=tree[rt].mn[i]=a[id].pos[i];
		return rt;
	}
	void pushup(int rt)
	{
		for(int i=0;i<=1;i++)
		{
			tree[rt].mx[i]=tree[rt].mn[i]=tree[rt].pos[i];
			if(lson(rt)!=0)
			{
				tree[rt].mx[i]=max(tree[rt].mx[i],tree[lson(rt)].mx[i]);
				tree[rt].mn[i]=min(tree[rt].mn[i],tree[lson(rt)].mn[i]);
			}
			if(rson(rt)!=0)
			{
				tree[rt].mx[i]=max(tree[rt].mx[i],tree[rson(rt)].mx[i]);
				tree[rt].mn[i]=min(tree[rt].mn[i],tree[rson(rt)].mn[i]);
			}
		}
	}
	void build(int &rt,int l,int r,int dir)
	{
		int mid=(l+r)/2;  cur=dir;
		nth_element(a+l,a+mid,a+r+1,cmp);  rt=build_rt(mid);
		if(l<=mid-1)  build(lson(rt),l,mid-1,dir^1);
		if(mid+1<=r)  build(rson(rt),mid+1,r,dir^1);
		pushup(rt);
	}
	ll cost(int rt,int pos)
	{
		ll ans=0;
		for(int i=0;i<=1;i++)
		{
			if(a[pos].pos[i]<tree[rt].mn[i])  ans+=tree[rt].mn[i]-a[pos].pos[i];
			if(a[pos].pos[i]>tree[rt].mx[i])  ans+=a[pos].pos[i]-tree[rt].mx[i];
		}
		return ans;
	}
	void query(int rt,int l,int r,int pos)
	{
		int mid=(l+r)/2;
		if(rt!=pos&&get_dis(rt,pos)<q.top())
		{
			q.pop();  q.push(get_dis(rt,pos));
		}
		ll fl=((l<=mid-1)?cost(lson(rt),pos):inf);
		ll fr=((mid+1<=r)?cost(rson(rt),pos):inf); 
		if(fl<q.top()&&fr<q.top())
		{
			if(fl<fr)
			{
				query(lson(rt),l,mid-1,pos);
				if(fr<q.top())  query(rson(rt),mid+1,r,pos);
			}
			else
			{
				query(rson(rt),mid+1,r,pos);
				if(fl<q.top())  query(lson(rt),l,mid-1,pos);
			}
		}
		else  if(fl<q.top())  query(lson(rt),l,mid-1,pos);
		else  if(fr<q.top())  query(rson(rt),mid+1,r,pos);
	}
}K;
int main()
{
// #define Isaac
#ifdef Isaac
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
#endif
	int n,k,i;
	cin>>n>>k;  k*=2;
	for(i=1;i<=n;i++)  cin>>a[i].pos[0]>>a[i].pos[1];
	for(i=1;i<=k;i++)  q.push(inf);
	K.build(K.root,1,n,0);
	for(i=1;i<=n;i++)  K.query(K.root,1,n,i);
	for(i=k;i>=1;i--)
	{
		ans[i]=q.top();  q.pop();
	}
	for(i=1;i<=k;i+=2)  cout<<ans[i]<<endl;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...