[NOI2019] 弹跳

题目描述

跳蚤国有 \(n\) 座城市,分别编号为 \(1 - n\)\(1\) 号城市为首都。所有城市分布在一个\(w \times h\) 范围的网格上。每座城市都有一个整数坐标 \((x, y) (1 \leq x \leq w, 1 \leq y \leq h)\),不同城市的坐标不相同。

在跳蚤国中共有 \(m\) 个弹跳装置,分别编号为 \(1 - m\),其中 \(i\) 号弹跳装置位于 \(p_i\) 号城市,并具有参数 \(t_i, L_i, R_i, D_i, U_i\)。利用该弹跳装置,跳蚤可花费 \(t_i (t_i > 0)\) 个单位时间,从 \(p_i\) 号城市跳至坐标满足 \(L_i \leq x \leq R_i, D_i \leq y \leq U_i (1 \leq L_i \leq R_i \leq w, 1 \leq D_i \leq U_i \leq h)\) 的任意一座城市。需要注意的是,一座城市中可能存在多个弹跳装置,也可能没有弹跳装置。

由于城市间距离较远,跳蚤们必须依靠弹跳装置出行。具体来说,一次出行将经过
若干座城市,依次经过的城市的编号可用序列 \(a_0, a_1, \cdots , a_k\) 表示;在此次出行中,依次利用的弹跳装置的编号可用序列 \(b_1, b_2, \cdots , b_k\) 表示。其中每座城市可在序列 \(\{a_j\}\) 中出现任意次,每个弹跳装置也可在序列 \(\{b_j\}\) 中出现任意次,且满足,对于每个 \(j (1 \leq j \leq k)\),编号为 \(b_j\) 的弹跳装置位于城市 \(a_{j-1}\),且跳蚤能通过该弹跳装置跳至城市 \(a_j\)。我们称这是一次从城市 \(a_0\) 到城市 \(a_k\) 的出行,其进行了 \(k\) 次弹跳,共花费 \(\sum^k_{i=1} t_{b_{i}}\) 个单位时间。

现在跳蚤国王想知道,对于跳蚤国除首都(\(1\) 号城市)外的每座城市,从首都出发,到达该城市最少需要花费的单位时间。跳蚤国王保证,对每座城市,均存在从首都到它的出行方案。

\(1 \leq n \leq 70000 , 1 \leq m \leq 150000 , 1 \leq w, h \leq n , 1 \leq t_i \leq 10000\)

尝试用 KDT 优化最短路。

将一整个矩形及其距离一起丢到堆里。那么每次从堆里面去除矩形之后,我们要找到所有矩形内还没有松驰过的点,可以用 KDT 维护。找到之后更改这个点能到的所有矩形的距离。

#include<bits/stdc++.h>
using namespace std;
const int N=1.5e5+5,INF=2e9;
typedef long long LL;
int n,m,w,h,l[N],r[N],u[N],d[N],t[N],rt;
vector<int>g[N];
int read()
{
	int s=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')
		ch=getchar();
	while(ch>='0'&&ch<='9')
		s=s*10+ch-48,ch=getchar();
	return s;
}
struct node{
	int v;
	LL w;
	bool operator<(const node&n)const{
		return w>n.w;
	}
};
struct dian{
	int x,y,id;
	bool operator<(const dian&n)const{
		return x<n.x;
	}
};
priority_queue<node>q;
LL dis[N];
int cmp(dian a,dian b)
{
	return a.y<b.y;
}
struct KDT{
	int mny[N],mnx[N],mxy[N],mxx[N],c[N],s[N],idx,lc[N],rc[N];
	dian a[N],id[N];
	int build(int l,int r,int p)
	{
		if(l>r)
			return 0;
		int md=l+r>>1,x=++idx;
		s[x]=1;
		if(p)
			nth_element(a+l,a+md+1,a+r+1);
		else
			nth_element(a+l,a+md+1,a+r+1,cmp);
		lc[x]=build(l,md-1,p^1);
		rc[x]=build(md+1,r,p^1);
		mnx[x]=min({mnx[lc[x]],mnx[rc[x]],a[md].x});
		mny[x]=min({mny[lc[x]],mny[rc[x]],a[md].y});
		mxx[x]=max({mxx[lc[x]],mxx[rc[x]],a[md].x});
		mxy[x]=max({mxy[lc[x]],mxy[rc[x]],a[md].y});
		id[x]=a[md];
		c[x]=c[lc[x]]+c[rc[x]]+s[x];
		return x;
	}
	int find(int o,int l,int r,int d,int u)
	{
		if(!c[o])
			return 0;
		if(l>mxx[o]||r<mnx[o]||d>mxy[o]||u<mny[o])
			return 0;
		if(s[o])
		{
			if(l<=id[o].x&&id[o].x<=r&&d<=id[o].y&&id[o].y<=u)
			{
				s[o]=0;
				c[o]=c[lc[o]]+c[rc[o]];
				return id[o].id;
			}
		}
		int k=find(lc[o],l,r,d,u);
		if(!k)
			k=find(rc[o],l,r,d,u);
		c[o]=c[lc[o]]+c[rc[o]]+s[o];
		return k;
	}
}s;
void dijkstra()
{
	q.push((node){0,0});
	while(!q.empty())
	{
		int k=q.top().v,x;
		LL w=q.top().w;
		q.pop();
		while(x=s.find(rt,l[k],r[k],d[k],u[k]))
		{
			dis[x]=w;
			for(int j=0;j<g[x].size();j++)
				q.push((node){g[x][j],w+t[g[x][j]]});
		}
	}
}
int main()
{
	n=read(),m=read(),w=read(),h=read();
	for(int i=1;i<=n;i++)
		s.a[i].x=read(),s.a[i].y=read(),s.a[i].id=i;
	l[0]=r[0]=s.a[1].x,d[0]=u[0]=s.a[1].y;
	s.mnx[0]=s.mny[0]=INF;
	rt=s.build(1,n,0);
	for(int i=1,p;i<=m;i++)
		scanf("%d%d%d%d%d%d",&p,t+i,l+i,r+i,d+i,u+i),g[p].push_back(i);
	dijkstra();
	for(int i=2;i<=n;i++)
		printf("%lld\n",dis[i]);
}
posted @ 2023-08-24 18:08  灰鲭鲨  阅读(20)  评论(0编辑  收藏  举报