[Luogu P5471] NOI 2019 D2T1 弹跳

Posted on 2020-06-01 21:35  opethrax  阅读(215)  评论(1编辑  收藏  举报

NOI 2019 D2T1 弹跳

题目大意:给定一个 \(W\times H\) 的平面,上面有 \(n\) 个城市 \((x_i,y_i)\),在 \(n\) 个城市中分布着 \(m\) 个装置,每一个装置都可以从城市 \(i\) 花费 \(t\) 时间到区域 \((D,L),(U,R)\) 内的另一城市 \((x_j,y_j)\)。现在从 \(1\) 号城市出发前往其他城市,求到每一个城市所需的最短时间

数据范围:\(1\leq L,R,U,D\leq W,H\leq N\leq 7\times 10^4,1\leq M\leq 1.5\times 10^5,t\leq 10000\)

题面大意求最短路,但是在一个平面上,逐个点处理时间空间上都不允许。

考虑 Dijkstra 算法,把边当做点处理放进队列。

遍历从 \(1\) 号节点出发的所有边,每抵达一个点,就把该点的所有边放进队列中,优先关键字:从开始走到当前选择的边,所需的时间。转移用树套树维护,外面的线段树维护横坐标,里面的维护纵坐标,查找一个区域的点在里面的树上二分,总复杂度 \(O(n\log^2 n+n\log n)\)

代码:

#include<stdio.h>
#include<string.h>
#include<algo#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;

template<class T>void read(T &x){
	x=0; char c=getchar();
	while(c<'0'||'9'<c)c=getchar();
	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
}
typedef pair<int,int> pr;
#define mp make_pair

const int N=150007;
const int M=150007;

int n,m,W,H;

struct dvc{
	int t,l,r,d,u;
}a[N];
int y[N],dis[N];
bool vis[N];

vector<int>e[N];
priority_queue< pr,vector<pr>,greater<pr> >q;
multiset<pr>s[M<<2];

void add(int l,int r,int p,int x,int i){
	s[p].insert(mp(y[i],i));
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(x<=mid)add(l,mid,p<<1,x,i);
	else add(mid+1,r,p<<1|1,x,i);
}

void upd(int l,int r,int p,int i,int d){
	if(r<a[i].l||a[i].r<l)return ;
	if(a[i].l<=l&&r<=a[i].r){
		multiset<pr>::iterator it=s[p].lower_bound(mp(a[i].d,0)),tt;
		int k;
		while(it!=s[p].end()&&(*it).first<=a[i].u){
			k=(*it).second;
			if(!vis[k]){
				vis[k]=1; dis[k]=d;
				for(int i=0;i<e[k].size();i++)
					q.push(pr(d+a[e[k][i]].t,e[k][i]));
			}
			tt=it; it++; s[p].erase(tt);
		}
		return ;
	}
	int mid=(l+r)>>1;
	upd(l,mid,p<<1,i,d); upd(mid+1,r,p<<1|1,i,d);
}

int main(){
	read(n); read(m); read(W); read(H);
	int x;
	for(int i=1;i<=n;i++){
		read(x); read(y[i]);
		add(1,W,1,x,i);
	}
	for(int i=1;i<=m;i++){
		read(x); read(a[i].t);
		read(a[i].l); read(a[i].r);
		read(a[i].d); read(a[i].u);
		e[x].push_back(i);
	}
	for(int i=0;i<e[1].size();i++)
		q.push(pr(a[e[1][i]].t,e[1][i]));
	vis[1]=1; 
	while(!q.empty()){
		int i=q.top().second,d=q.top().first; q.pop();
		upd(1,n,1,i,d);
	}
	for(int i=2;i<=n;i++)printf("%d\n",dis[i]);
	return 0;
}