zoukankan      html  css  js  c++  java
  • 「NOI2019」弹跳(KD树)

    题意:w×h网格中有n个点,m条边。每条边可以从p点花费t时间到一个矩形中的任意点,求1号点到每个点的最少时间。
    (1<=w,h<=n<=70000,1<=m<=150000)
    时间2s,空间128M

    本题如果放在序列上,使用线段树建图,可以做到(O(mlogn))的复杂度,通过数据分治可以获得72分。
    对于二维问题可以想到将线段树变为二维线段树,然而会被卡空间。
    考虑此题暴力Dij的本质:就是每次找最小的点,然后把一个矩形中大于z的数都改为z,再删除这个点。
    看到矩形修改,可以想到KD树。
    KD树的空间复杂度是(O(n))的,很优秀。
    在矩形修改时,采用类似线段树的方法:如果当前矩形与修改的矩形没有交,就直接返回。如果被包含,则直接打标记。
    但与线段树不同的:还需要考虑当前的点是否在矩形内,如果在则直接修改这个点。
    这就是KD树处理矩形的方法。
    时间复杂度:(O(msqrt{n}))
    删除一个点可以打一个特殊标记实现。
    把这个写上后,会发现超时。
    考虑剪枝:如果z大于当前点的标记,就直接返回。
    这样就能过了。

    代码:

    #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
    ",dis[i]);
    	return 0;
    }
    
  • 相关阅读:
    Spring Boot 入门
    门罗币(MONERO)钱包生成教程
    数据库 一对多,多对多 表设计
    使用nginx+lua脚本读写redis缓存
    在Spring MVC中使用注解的方式校验RequestParams
    MySQL命名、设计及使用规范《MySQL命名、设计及使用规范》
    Mycat分表分库
    Go在Ubuntu 14.04 64位上的安装过程
    Android获取设备屏幕宽高像素值的两个方法
    php_curl.dll libssh2.dll 始终无法加载的原因 及解决办法
  • 原文地址:https://www.cnblogs.com/lnzwz/p/11251083.html
Copyright © 2011-2022 走看看