LOJ#3159. 「NOI2019」弹跳(四分树+dijkstra)

21 篇文章 0 订阅
6 篇文章 0 订阅

传送门
n 2 n^2 n2暴力显然,考虑优化。
有一种想法是使用四分树/kd-tree/树套树,发现你并不能得到 100 p t s 100pts 100pts的好成绩(空间会炸掉)
考试的时候比较智熄,先暴力四分树建边然后跑dijkstra,于是动态内存炸了。。。 88 p t s 88pts 88pts滚粗。
那剩下那 12 p t s 12pts 12pts如何拿呢?
我们考虑只用四分树加入点,这样的空间开销仅有 O ( n l o g n ) O(nlog_n) O(nlogn),然后把一个点到一个矩形的边存下来,每次跑 d i j k s t r a dijkstra dijkstra的时候暴力在四分树上找被松弛的点把它们松弛之后加入堆即可。
88 p t s 88pts 88pts代码:

#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
#define x1 ldxx1
#define x2 ldxx2
#define y1 ldxy1
#define y2 ldxy2
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int N=70005,M=150005;
typedef pair<int,int> pii;
int pos[N],tot=0;
int son[M*20][4],dis[M*20];
bool in[M*20];
vector<pii>e[N];
int n,W,H,m,rt=0;
const int mogic=1e5+7;
struct Hash_table{
	vector<int>ori[mogic],val[mogic];
	inline int query(int x){
		for(ri t=x%mogic,i=ori[t].size()-1;~i;--i)if(ori[t][i]==x)return val[t][i];
		return -1;
	}
	inline void update(int x,int v){
		int t=x%mogic;
		ori[t].push_back(x),val[t].push_back(v);
	}
}mp;
inline void insert(int&p,int x1,int y1,int x2,int y2,int kx,int ky,int id){
	if(!p)p=++tot;
	dis[p]=1e9;
	if(x1==x2&&y1==y2){mp.update(p,id),pos[id]=p;return;}
	int mx=x1+x2>>1,my=y1+y2>>1;
	if(kx<=mx&&ky<=my)insert(son[p][0],x1,y1,mx,my,kx,ky,id);
	if(kx<=mx&&ky>my)insert(son[p][1],x1,my+1,mx,y2,kx,ky,id);
	if(kx>mx&&ky<=my)insert(son[p][2],mx+1,y1,x2,my,kx,ky,id);
	if(kx>mx&&ky>my)insert(son[p][3],mx+1,my+1,x2,y2,kx,ky,id);
}
int ldxid,ldxw,qx1,qx2,qy1,qy2;
int cnt=0,cnt1=0;
inline bool check(int x1,int y1,int x2,int y2){return !((x2<qx1)||(x1>qx2)||(y2<qy1)||(y1>qy2));}
inline void addedge(int p,int x1,int y1,int x2,int y2){
	++cnt;
	if(qx1<=x1&&x2<=qx2&&qy1<=y1&&y2<=qy2){e[ldxid].push_back(pii(p,ldxw)),++cnt1;return;}
	int mx=x1+x2>>1,my=y1+y2>>1;
	if(son[p][0]&&check(x1,y1,mx,my))addedge(son[p][0],x1,y1,mx,my);
	if(son[p][1]&&check(x1,my+1,mx,y2))addedge(son[p][1],x1,my+1,mx,y2);
	if(son[p][2]&&check(mx+1,y1,x2,my))addedge(son[p][2],mx+1,y1,x2,my);
	if(son[p][3]&&check(mx+1,my+1,x2,y2))addedge(son[p][3],mx+1,my+1,x2,y2);
}
inline void dijkstra(){
	priority_queue<pii,vector<pii>,greater<pii> >q;
	q.push(pii(dis[pos[1]]=0,pos[1]));
	while(!q.empty()){
		int x=q.top().se;
		q.pop();
		if(in[x])continue;
		in[x]=1;
		int p=mp.query(x);
		if(p==-1){
			for(ri i=0,v;i<4;++i){
				if(!(v=son[x][i]))continue;
				if(dis[v]>dis[x])dis[v]=dis[x],q.push(pii(dis[v],v));
			}
		}
		else{
			for(ri i=0,v,w;i<e[p].size();++i){
				v=e[p][i].fi,w=e[p][i].se;
				if(dis[v]>dis[x]+w)dis[v]=dis[x]+w,q.push(pii(dis[v],v));
			}
		}
	}
	for(ri i=2;i<=n;++i)cout<<dis[pos[i]]<<'\n';
}
int main(){
    freopen("jump.in","r",stdin);
    freopen("jump.out","w",stdout);
	n=read(),m=read(),W=read(),H=read();
	for(ri i=1,x,y;i<=n;++i){
		x=read(),y=read();
		insert(rt,1,1,W,H,x,y,i);
	}
	for(ri i=1,w,x1,y1,x2,y2,id;i<=m;++i){
		ldxid=read(),ldxw=read(),qx1=read(),qx2=read(),qy1=read(),qy2=read();
		addedge(rt,1,1,W,H);
	}
	dijkstra();
	return 0;
}

100 p t s 100pts 100pts代码:

#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
#define x1 ldxx1
#define x2 ldxx2
#define y1 ldxy1
#define y2 ldxy2
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int N=70005,M=150005;
typedef pair<int,int> pii;
int tot=0;
int son[M*20][4],dis[M*20];
bool in[M*20];
vector<int>e[M*20];
vector<int>g[N];
int n,W,H,m,rt=0;
inline void insert(int&p,int x1,int y1,int x2,int y2,int kx,int ky,int id){
	if(!p)p=++tot;
	dis[p]=1e9;
	if(x1==x2&&y1==y2){e[p].push_back(id);return;}
	int mx=x1+x2>>1,my=y1+y2>>1;
	if(kx<=mx&&ky<=my)insert(son[p][0],x1,y1,mx,my,kx,ky,id);
	if(kx<=mx&&ky>my)insert(son[p][1],x1,my+1,mx,y2,kx,ky,id);
	if(kx>mx&&ky<=my)insert(son[p][2],mx+1,y1,x2,my,kx,ky,id);
	if(kx>mx&&ky>my)insert(son[p][3],mx+1,my+1,x2,y2,kx,ky,id);
}
int pos[M],val[M],qx1[M],qx2[M],qy1[M],qy2[M];
priority_queue<pii,vector<pii>,greater<pii> >q;
inline bool check(int x1,int y1,int x2,int y2,int id){return !((x2<qx1[id])||(x1>qx2[id])||(y2<qy1[id])||(y1>qy2[id]));}
inline void build(int p){
	if(!p)return;
	for(ri i=0;i<4;++i){
		if(!son[p][i])continue;
		e[p].push_back(son[p][i]);
		build(son[p][i]);
	}
}
inline void addedge(int p,int x1,int y1,int x2,int y2,int id){
	if(!p||dis[p]<=dis[pos[id]]+val[id])return;
	if(qx1[id]<=x1&&x2<=qx2[id]&&qy1[id]<=y1&&y2<=qy2[id]){
		q.push(pii(dis[p]=dis[pos[id]]+val[id],p));
		return;
	}
	int mx=x1+x2>>1,my=y1+y2>>1;
	if(son[p][0]&&check(x1,y1,mx,my,id))addedge(son[p][0],x1,y1,mx,my,id);
	if(son[p][1]&&check(x1,my+1,mx,y2,id))addedge(son[p][1],x1,my+1,mx,y2,id);
	if(son[p][2]&&check(mx+1,y1,x2,my,id))addedge(son[p][2],mx+1,y1,x2,my,id);
	if(son[p][3]&&check(mx+1,my+1,x2,y2,id))addedge(son[p][3],mx+1,my+1,x2,y2,id);
}
inline void dijkstra(){
	q.push(pii(dis[1]=0,1));
	while(!q.empty()){
		int x=q.top().se;
		q.pop();
		if(in[x])continue;
		in[x]=1;
		if(x<=n)for(ri i=0;i<g[x].size();++i)addedge(rt,1,1,W,H,g[x][i]);
		else{
			for(ri i=0,v,w;i<e[x].size();++i){
				v=e[x][i];
				if(dis[v]>dis[x])q.push(pii(dis[v]=dis[x],v));
			}
		}
	}
	for(ri i=2;i<=n;++i)cout<<dis[i]<<'\n';
}
int main(){
    freopen("jump.in","r",stdin);
    freopen("jump.out","w",stdout);
	n=read(),m=read(),W=read(),H=read();
	tot=n;
	for(ri i=1,x,y;i<=n;++i){
		dis[i]=1e9;
		x=read(),y=read();
		insert(rt,1,1,W,H,x,y,i);
	}
	for(ri i=1,w,x1,y1,x2,y2,id;i<=m;++i){
		pos[i]=read(),val[i]=read(),qx1[i]=read(),qx2[i]=read(),qy1[i]=read(),qy2[i]=read();
		g[pos[i]].push_back(i);
	}
	build(rt);
	dijkstra();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值