zoukankan      html  css  js  c++  java
  • #分治,Dijkstra#洛谷 3350 [ZJOI2016]旅行者

    题目

    给定一张(n*m)的网格图,(q)次询问两点之间距离
    (n*mleq 2*10^4,qleq 10^5)


    分析

    首先floyd会TLE,考虑两点间距离可以由两段拼凑起来,
    那么枚举中间点然后跑单源最短路,但是这样与floyd时间复杂度无异,
    一些中间点实际上完全不需要,考虑分治,每次选取中线上的点在子图内跑单源最短路
    据说时间复杂度是(O(nmsqrt{nm}log{nm}))


    代码

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define rr register
    using namespace std;
    const int N=20011,inf=0x3f3f3f3f; struct node{int y,w,next;}e[N<<2];
    struct rec{int lx,ly,rx,ry,rk;}q[N*5],q1[N*5],q2[N*5];
    struct Two{
    	int d,x;
    	inline bool operator <(const Two &t)const{
    		return d<t.d;
    	}
    };
    int as[N],Cnt,et=1,Q,dis[N],ans[N*5],n,m,Lx,Ly,Rx,Ry; Two heap[N];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline void add(int x,int y,int w){
    	e[++et]=(node){y,w,as[x]},as[x]=et;
    	e[++et]=(node){x,w,as[y]},as[y]=et; 
    }
    inline signed min(int a,int b){return a<b?a:b;}
    inline void Push(Two w){
    	heap[++Cnt]=w;
    	rr int x=Cnt;
    	while (x>1){
    		if (heap[x]<heap[x>>1])
    		    swap(heap[x],heap[x>>1]),x>>=1;
    		else return; 
    	}
    }
    inline void Pop(){
    	heap[1]=heap[Cnt--];
    	rr int x=1;
    	while ((x<<1)<=Cnt){
    		rr int y=x<<1;
    		if (y<Cnt&&heap[y+1]<heap[y]) ++y;
    		if (heap[y]<heap[x]) swap(heap[x],heap[y]),x=y;
    		    else return;
    	}
    }
    inline signed rk(int x,int y){return (x-1)*m+y;}
    inline bool Into(int Rk){
    	rr int x=(Rk-1)/m+1,y=Rk-(x-1)*m;
    	return Lx<=x&&x<=Rx&&Ly<=y&&y<=Ry;
    }
    inline void Dijkstra(int S){
    	if (dis[S]){
    		for (rr int i=Lx;i<=Rx;++i)
    	    for (rr int j=Ly;j<=Ry;++j)
    		    if (rk(i,j)!=S) dis[rk(i,j)]+=dis[S];
    	}else for (rr int i=Lx;i<=Rx;++i)
    	    for (rr int j=Ly;j<=Ry;++j)
    	        dis[rk(i,j)]=inf;
    	heap[++Cnt]=(Two){0,S},dis[S]=0;
    	while (Cnt){
    		rr Two t=heap[1];
    		Pop(); if (t.d!=dis[t.x]) continue;
    		for (rr int i=as[t.x];i;i=e[i].next)
    		if (Into(e[i].y)&&dis[e[i].y]>dis[t.x]+e[i].w){
    			dis[e[i].y]=dis[t.x]+e[i].w;
    			Push((Two){dis[e[i].y],e[i].y});
    		}
    	}
    }
    inline void dfs(int lx,int rx,int ly,int ry,int l,int r){
    	if (l>r) return;
    	if (lx==rx&&ly==ry){
    		for (rr int i=l;i<=r;++i) ans[q[i].rk]=0;
    		return;
    	}
    	Lx=lx,Rx=rx,Ly=ly,Ry=ry;
    	if (rx-lx>ry-ly){
    		rr int mid=(lx+rx)>>1,tot1=0,tot2=0;
    		for (rr int i=ly;i<=ry;++i){
    			Dijkstra(rk(mid,i));
    			for (rr int j=l;j<=r;++j)
    			    ans[q[j].rk]=min(ans[q[j].rk],dis[rk(q[j].lx,q[j].ly)]+dis[rk(q[j].rx,q[j].ry)]);
    		}
    		for (rr int i=l;i<=r;++i){
    			if (lx<=q[i].lx&&q[i].lx<=mid&&lx<=q[i].rx&&q[i].rx<=mid) q1[++tot1]=q[i];
    			if (mid+1<=q[i].lx&&q[i].lx<=rx&&mid+1<=q[i].rx&&q[i].rx<=rx) q2[++tot2]=q[i];
    		}
    		for (rr int i=1;i<=tot1;++i) q[i+l-1]=q1[i];
    		for (rr int i=1;i<=tot2;++i) q[r-i+1]=q2[i];
    		dfs(lx,mid,ly,ry,l,l+tot1-1);
    		dfs(mid+1,rx,ly,ry,r-tot2+1,r);
        }else{
     		rr int mid=(ly+ry)>>1,tot1=0,tot2=0;
    		for (rr int i=lx;i<=rx;++i){
    			Dijkstra(rk(i,mid));
    			for (rr int j=l;j<=r;++j)
    			    ans[q[j].rk]=min(ans[q[j].rk],dis[rk(q[j].lx,q[j].ly)]+dis[rk(q[j].rx,q[j].ry)]);
    		}
    		for (rr int i=l;i<=r;++i){
    			if (ly<=q[i].ly&&q[i].ly<=mid&&ly<=q[i].ry&&q[i].ry<=mid) q1[++tot1]=q[i];
    			if (mid+1<=q[i].ly&&q[i].ly<=ry&&mid+1<=q[i].ry&&q[i].ry<=ry) q2[++tot2]=q[i];
    		}
    		for (rr int i=1;i<=tot1;++i) q[i+l-1]=q1[i];
    		for (rr int i=1;i<=tot2;++i) q[r-i+1]=q2[i];
    		dfs(lx,rx,ly,mid,l,l+tot1-1);
    		dfs(lx,rx,mid+1,ry,r-tot2+1,r);   	
    	}
    }
    signed main(){
    	n=iut(),m=iut();
    	for (rr int i=1;i<=n;++i)
    	for (rr int j=1;j<m;++j)
    		add(rk(i,j),rk(i,j+1),iut());
    	for (rr int i=1;i<n;++i)
    	for (rr int j=1;j<=m;++j)
    	    add(rk(i,j),rk(i+1,j),iut());
    	Q=iut();
    	for (rr int i=1;i<=Q;++i)
    	    ans[i]=inf,q[i]=(rec){iut(),iut(),iut(),iut(),i};
    	dfs(1,n,1,m,1,Q);
    	for (rr int i=1;i<=Q;++i) print(ans[i]),putchar(10);
    	return 0;
    }
    
  • 相关阅读:
    一个日期类型接口参数的构造思路
    python接口测试:如何将A接口的返回值传递给B接口
    关于查询类接口的一些总结
    (六十八)c#Winform自定义控件-DEMO整理-HZHControls
    (六十七)c#Winform自定义控件-柱状图-HZHControls
    (六十六)c#Winform自定义控件-图标-HZHControls
    (六十五)c#Winform自定义控件-思维导图/组织架构图(工业)-HZHControls
    (六十四)c#Winform自定义控件-温度计(工业)-HZHControls
    (六十三)c#Winform自定义控件-箭头(工业)-HZHControls
    (六十二)c#Winform自定义控件-警灯(工业)-HZHControls
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14911564.html
Copyright © 2011-2022 走看看