「NOI2019」彈跳(KD樹)

題意:w×h網格中有n個點,m條邊。每條邊能夠從p點花費t時間到一個矩形中的任意點,求1號點到每一個點的最少時間。 $1<=w,h<=n<=70000,1<=m<=150000$ 時間2s,空間128Mui

本題若是放在序列上,使用線段樹建圖,能夠作到$O(mlogn)$的複雜度,經過數據分治能夠得到72分。 對於二維問題能夠想到將線段樹變爲二維線段樹,然而會被卡空間。 考慮此題暴力Dij的本質:就是每次找最小的點,而後把一個矩形中大於z的數都改成z,再刪除這個點。 看到矩形修改,能夠想到KD樹。 KD樹的空間複雜度是$O(n)$的,很優秀。 在矩形修改時,採用相似線段樹的方法:若是當前矩形與修改的矩形沒有交,就直接返回。若是被包含,則直接打標記。 但與線段樹不一樣的:還須要考慮當前的點是否在矩形內,若是在則直接修改這個點。 這就是KD樹處理矩形的方法。 時間複雜度:$O(m\sqrt{n})$。 刪除一個點能夠打一個特殊標記實現。 把這個寫上後,會發現超時。 考慮剪枝:若是z大於當前點的標記,就直接返回。 這樣就能過了。code

代碼:io

#include <stdio.h>
#include <stdlib.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
struct SPx
{
	int x,y,i;
	SPx(){}
	SPx(int X,int Y,int I)
	{
		x=X;y=Y;i=I;
	}
};
int cmpx(const void*a,const void*b)
{
	return ((SPx*)a)->x-((SPx*)b)->x;
}
int cmpy(const void*a,const void*b)
{
	return ((SPx*)a)->y-((SPx*)b)->y;
}
int cl[70010],cr[70010],fa[70010],lx[70010],rx[70010],ly[70010],ry[70010];
int zx[70010],wz[70010],qz[70010],ld[70010],inf=2000000000,root;
bool bk[70010];
void update(int x)
{
	if(bk[x])
		zx[x]=inf,wz[x]=-1;
	else
		zx[x]=qz[x],wz[x]=x;
	if(cl[x]!=0&&wz[cl[x]]!=-1&&zx[cl[x]]<=zx[x])
		zx[x]=zx[cl[x]],wz[x]=wz[cl[x]];
	if(cr[x]!=0&&wz[cr[x]]!=-1&&zx[cr[x]]<=zx[x])
		zx[x]=zx[cr[x]],wz[x]=wz[cr[x]];
}
void pur(int x,int y)
{
	if(ld[x]!=-1&&y>=ld[x])
		return;
	ld[x]=y;
	if(qz[x]>y)qz[x]=y;
	if(zx[x]>y)zx[x]=y;
}
void pushdown(int x)
{
	if(ld[x]==-1)return;
	if(cl[x]!=0)pur(cl[x],ld[x]);
	if(cr[x]!=0)pur(cr[x],ld[x]);
	ld[x]=-1;
}
void clean(int x)
{
	if(fa[x]!=0)
		clean(fa[x]);
	pushdown(x);
}
void del(int x)
{
	clean(x);
	bk[x]=true;
	for(int i=x;i!=0;i=fa[i])
		update(i);
}
int buix(SPx sz[70010],int l,int r);
int buiy(SPx sz[70010],int l,int r);
void pushup(int rt)
{
	if(cl[rt]!=0)
	{
		lx[rt]=min(lx[rt],lx[cl[rt]]);rx[rt]=max(rx[rt],rx[cl[rt]]);
		ly[rt]=min(ly[rt],ly[cl[rt]]);ry[rt]=max(ry[rt],ry[cl[rt]]);
		fa[cl[rt]]=rt;
	}
	if(cr[rt]!=0)
	{
		lx[rt]=min(lx[rt],lx[cr[rt]]);rx[rt]=max(rx[rt],rx[cr[rt]]);
		ly[rt]=min(ly[rt],ly[cr[rt]]);ry[rt]=max(ry[rt],ry[cr[rt]]);
		fa[cr[rt]]=rt;
	}
}
bool fugai(int Lx,int Rx,int Ly,int Ry,int lx,int rx,int ly,int ry)
{
	return Lx<=lx&&rx<=Rx&&Ly<=ly&&ry<=Ry;
}
bool fenli(int Lx,int Rx,int Ly,int Ry,int lx,int rx,int ly,int ry)
{
	return Lx>rx||lx>Rx||Ly>ry||ly>Ry;
}
int X[70010],Y[70010];
int buix(SPx sz[70010],int l,int r)
{
	if(l>=r)return 0;
	qsort(sz+l,r-l,sizeof(SPx),cmpx);
	int m=(l+r-1)>>1,rt=sz[m].i;
	lx[rt]=rx[rt]=sz[m].x;
	ly[rt]=ry[rt]=sz[m].y;
	cl[rt]=buiy(sz,l,m);
	cr[rt]=buiy(sz,m+1,r);
	pushup(rt);
	return rt;
}
int buiy(SPx sz[70010],int l,int r)
{
	if(l>=r)return 0;
	qsort(sz+l,r-l,sizeof(SPx),cmpy);
	int m=(l+r-1)>>1,rt=sz[m].i;
	lx[rt]=rx[rt]=sz[m].x;
	ly[rt]=ry[rt]=sz[m].y;
	cl[rt]=buix(sz,l,m);
	cr[rt]=buix(sz,m+1,r);
	pushup(rt);
	return rt;
}
void songc(int i,int Lx,int Rx,int Ly,int Ry,int z)
{
	if(ld[i]!=-1&&z>ld[i])
		return;
	if(fenli(Lx,Rx,Ly,Ry,lx[i],rx[i],ly[i],ry[i]))
		return;
	if(fugai(Lx,Rx,Ly,Ry,lx[i],rx[i],ly[i],ry[i]))
	{
		pur(i,z);
		return;
	}
	pushdown(i);
	if(fugai(Lx,Rx,Ly,Ry,X[i],X[i],Y[i],Y[i]))
	{
		if(qz[i]>z)
			qz[i]=z;
		update(i);
	}
	if(cl[i]!=0)
		songc(cl[i],Lx,Rx,Ly,Ry,z);
	if(cr[i]!=0)
		songc(cr[i],Lx,Rx,Ly,Ry,z);
	update(i);
}
void dfs(int u)
{
	if(cl[u]!=0)
		dfs(cl[u]);
	if(cr[u]!=0)
		dfs(cr[u]);
	update(u);
}
int dis[70010];
int fr[70010],ne[150010],x1[150010],x2[150010],y1[150010],y2[150010],w[150010],bs=0;
void addb(int a,int lx,int rx,int ly,int ry,int b)
{
	x1[bs]=lx;x2[bs]=rx;
	y1[bs]=ly;y2[bs]=ry;
	w[bs]=b;
	ne[bs]=fr[a];
	fr[a]=bs++;
}
SPx sz[70010];
void dij(int u,int n)
{
	for(int i=1;i<=n;i++)
		sz[i]=SPx(X[i],Y[i],i);
	root=buix(sz,1,n+1);
	for(int i=1;i<=n;i++)
		qz[i]=inf;
	qz[u]=0;
	dfs(root);
	while(1)
	{
		int t=wz[root],x=zx[root];
		if(t==-1)break;
		del(t);dis[t]=x;
		for(int i=fr[t];i!=-1;i=ne[i])
			songc(root,x1[i],x2[i],y1[i],y2[i],x+w[i]);
	}
}
int main()
{
	wz[0]=-1;
	int n,m,w,h;
	scanf("%d%d%d%d",&n,&m,&w,&h);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&X[i],&Y[i]);
	for(int i=1;i<=n;i++)
		fr[i]=ld[i]=-1;
	for(int i=0;i<m;i++)
	{
		int p,t,l,r,d,u;
		scanf("%d%d%d%d%d%d",&p,&t,&l,&r,&d,&u);
		addb(p,l,r,d,u,t);
	}
	dij(1,n);
	for(int i=2;i<=n;i++)
		printf("%d\n",dis[i]);
	return 0;
}
相關文章
相關標籤/搜索