[LOJ3159][KD-tree][最短路]NOI2019:弹跳

LOJ3159

其实是一种类似kdtree思想的分治优化建图
stO zxyoi Orz

Code:

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=7e4+5,M=2e5,INF=0x3f3f3f3f;
int n,m,w,h;
struct point{
	int x,y;
	int id;
}p[N];
int que[N],cnt=0;
namespace kdt{
	int ls[N<<1],rs[N<<1],kd[N<<1],tot,rt;
	int U[N<<1],D[N<<1],L[N<<1],R[N<<1],siz[N<<1],id[N<<1];
	inline bool cmp1(const point &a,const point &b){return a.x<b.x;}
	inline bool cmp2(const point &a,const point &b){return a.y<b.y;}
	void build(int &rt,int l,int r,int u,int d,int ql,int qr,int last=0){
		rt=++tot;
		L[rt]=l,R[rt]=r,D[rt]=d,U[rt]=u;
		siz[rt]=qr-ql+1;
		if(ql==qr){
			id[rt]=p[ql].id;
			return;
		}
		if(u==d){
			kd[u]=1;
			if(last!=1) sort(p+ql,p+qr+1,cmp1);
			int mid=ql+qr>>1;
			build(ls[rt],l,p[mid].x,u,u,ql,mid,1);
			build(rs[rt],p[mid+1].x,r,u,u,mid+1,qr,1);
			return;
		}
		if(l==r){
			kd[l]=2;
			if(last!=2) sort(p+ql,p+qr+1,cmp2);
			int mid=ql+qr>>1;
			build(ls[rt],l,l,u,p[mid].y,ql,mid,2);
			build(rs[rt],l,l,p[mid+1].y,d,mid+1,qr,2);
			return;
		}
		kd[u]=3-last;
		if(kd[u]==3) kd[u]=1;
		if(kd[u]==1){
			sort(p+ql,p+qr+1,cmp1);
			int mid=ql+qr>>1,nu=INF,nd=0;
			for(int i=ql;i<=mid;i++) nu=min(nu,p[i].y),nd=max(nd,p[i].y);
			build(ls[rt],l,p[mid].x,nu,nd,ql,mid,1);
			nu=INF,nd=0;
			for(int i=mid+1;i<=qr;i++) nu=min(nu,p[i].y),nd=max(nd,p[i].y);
			build(rs[rt],p[mid+1].x,r,nu,nd,mid+1,qr,1);
		}
		else{
			sort(p+ql,p+qr+1,cmp2);
			int mid=ql+qr>>1,nl=INF,nr=0;
			for(int i=ql;i<=mid;i++) nl=min(nl,p[i].x),nr=max(nr,p[i].x);
			build(ls[rt],nl,nr,u,p[mid].y,ql,mid,2);
			nl=INF,nr=0;
			for(int i=mid+1;i<=qr;i++) nl=min(nl,p[i].x),nr=max(nr,p[i].x);
			build(rs[rt],nl,nr,p[mid+1].y,d,mid+1,qr,2);
		}
	}
	void get(int rt,int l,int r,int u,int d){
		if(!siz[rt]) return;
		if(r<L[rt] || R[rt]<l || d<U[rt] || D[rt]<u) return;
		if(id[rt]){
			siz[rt]=0;
			que[++cnt]=id[rt];
			return;
		}
		if(kd[rt]==1){
			if(l<=R[ls[rt]]) get(ls[rt],l,r,u,d);
			if(L[rs[rt]]<=r) get(rs[rt],l,r,u,d);
		}
		else{
			if(u<=D[ls[rt]]) get(ls[rt],l,r,u,d);
			if(U[rs[rt]]<=d) get(rs[rt],l,r,u,d);
		}
		siz[rt]=siz[ls[rt]]+siz[rs[rt]];
	}
}
struct mat{
	int l,r,u,d;ll c;
	mat(int _l,int _r,int _u,int _d,ll _c):l(_l),r(_r),u(_u),d(_d),c(_c){}
	friend inline bool operator > (const mat &a,const mat &b){return a.c>b.c;}
};
vector<mat>e[N];
priority_queue< mat,vector<mat>,greater<mat> >q;
int pt[N];ll dis[N];
inline void dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	for(int i=0;i<e[1].size();i++) q.push(e[1][i]);
	pt[1]=1;
	while(!q.empty()){
		int l=q.top().l,r=q.top().r,u=q.top().u,d=q.top().d;ll c=q.top().c;
		q.pop();cnt=0;
		kdt::get(kdt::rt,l,r,u,d);
		for(int i=1;i<=cnt;i++){
			int v=que[i];
			if(pt[v]) continue;
			pt[v]=1;
			dis[v]=c;
			for(int j=0;j<e[v].size();j++){
				q.push(mat(e[v][j].l,e[v][j].r,e[v][j].u,e[v][j].d,e[v][j].c+c));
			}
		}
	}
}
int mnx=INF,mxx=0,mny=INF,mxy=0;
int main(){
	n=read();m=read();w=read();h=read();
	for(int i=1;i<=n;i++){
		p[i].x=read(),p[i].y=read(),p[i].id=i;
		mnx=min(mnx,p[i].x);
		mxx=max(mxx,p[i].x);
		mny=min(mny,p[i].y);
		mxy=max(mxy,p[i].y);
	}
	kdt::build(kdt::rt,mnx,mxx,mny,mxy,1,n);
	for(int i=1;i<=m;++i){
		int u=read(),w=read(),L=read(),R=read(),U=read(),D=read();
		e[u].push_back(mat(L,R,U,D,w));
	}
	dijkstra();
	for(int i=2;i<=n;i++) cout<<dis[i]<<"\n";
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值