• BZOJ4456/UOJ#184[Zjoi2016]旅行者 分治 最短路


    原文链接http://www.cnblogs.com/zhouzhendong/p/8682133.html

    题目传送门 - BZOJ4456

    题目传送门 - UOJ#184

    题意

      $n imes m$的网格图$q$次询问两个格子之间的最短路。

      $n imes mleq 2 imes 10^4,qleq 10^5$且任何两个相邻格子之间的路径长度$leq 10^4$。

    题解

      考虑分治。

      对于当前网格图以及起点和终点都在当前网格图内的询问进行处理。

      考虑把当前网格图的长边作为分治对象。

      我们来分割长边。对于分割线上的一条格子(我们称为中线),我们求得其他格子到他的最短路。然后用来更新答案。

      把询问分成两种:

      1. 起点和终点分别处于中线两侧的,必然经过中线。

      2. 起点和终点在中线同一侧的,有可能经过中线,有可能不经过。

      然后更新完之后就分治被中线分开的两块网格,继续更新第2种询问。

      这题卡SPFA,最短路要写堆优化的Dijkstra。

      %%%jiry_2!吉老师SPFA在UOJ上面80分!震惊。(蒟蒻自带大常数QAQ只有40)

    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=20005,maxQ=100005,INF=1e9;
    struct Gragh{
    	static const int M=N*4;
    	int cnt,y[M],z[M],nxt[M],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,int c){
    		y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,m,Q,id[maxQ],tmp[maxQ];
    int HA(int a,int b){return (a-1)*m+b-1;}
    void HB(int v,int &a,int &b){a=v/m+1,b=v%m+1;}
    struct Query{
    	int s,t,ans;
    	void get(){
    		int x1,y1,x2,y2;
    		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    		s=HA(x1,y1),t=HA(x2,y2);
    		ans=s==t?0:INF;
    	}
    }q[maxQ];
    void buildg(){
    	g.clear();
    	int x;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<m;j++){
    			scanf("%d",&x);
    			g.add(HA(i,j),HA(i,j+1),x);
    			g.add(HA(i,j+1),HA(i,j),x);
    		}
    	for (int i=1;i<n;i++)
    		for (int j=1;j<=m;j++){
    			scanf("%d",&x);
    			g.add(HA(i,j),HA(i+1,j),x);
    			g.add(HA(i+1,j),HA(i,j),x);
    		}
    }
    int heap[N],pos[N],size,d[N];
    void heap_up(int x){
    	for (int y=x>>1;y>0&&d[heap[x]]<d[heap[y]];x=y,y=x>>1)
    		swap(pos[heap[x]],pos[heap[y]]),swap(heap[x],heap[y]);
    }
    void heap_down(int x){
    	for (int y=x<<1;y<=size;x=y,y=x<<1){
    		y|=y<size&&d[heap[y|1]]<d[heap[y]];
    		if (d[heap[y]]>d[heap[x]])
    			break;
    		swap(pos[heap[x]],pos[heap[y]]),swap(heap[x],heap[y]);
    	}
    }
    void heap_pop(){
    	pos[heap[1]]=0,heap[1]=heap[size--],pos[heap[1]]=1;
    	heap_down(1);
    }
    void heap_push(int x){
    	if (!pos[x])
    		heap[pos[x]=++size]=x;
    	heap_up(pos[x]);
    }
    void Dijkstra(int s,int x1,int y1,int x2,int y2){
    	int a,b,x,y;
    	memset(pos,0,sizeof pos);
    	memset(d,63,sizeof d);
    	size=0;
    	d[s]=0,heap_push(s);
    	while (size){
    		x=heap[1];
    		heap_pop();
    		for (int i=g.fst[x];i;i=g.nxt[i]){
    			HB(y=g.y[i],a,b);
    			if (x1<=a&&a<=x2&&y1<=b&&b<=y2&&d[y]>d[x]+g.z[i]){
    				d[y]=d[x]+g.z[i];
    				heap_push(y);
    			}
    		}
    	}
    }
    void solve(int x1,int y1,int x2,int y2,int L,int R){
    	if (L>R)
    		return;
    	if (x2-x1>y2-y1){
    		int mid=(x1+x2)/2;
    		for (int i=y1;i<=y2;i++){
    			Dijkstra(HA(mid,i),x1,y1,x2,y2);
    			for (int j=L;j<=R;j++)
    				q[id[j]].ans=min(q[id[j]].ans,d[q[id[j]].s]+d[q[id[j]].t]);
    		}
    		int Lr=L-1,Rl=R+1;
    		for (int j=L;j<=R;j++){
    			int x3=q[id[j]].s/m+1,x4=q[id[j]].t/m+1;
    			if (x3<mid&&x4<mid)
    				tmp[++Lr]=id[j];
    			if (x3>mid&&x4>mid)
    				tmp[--Rl]=id[j];
    		}
    		for (int j=L;j<=Lr;j++)
    			id[j]=tmp[j];
    		for (int j=Rl;j<=R;j++)
    			id[j]=tmp[j];
    		solve(x1,y1,mid-1,y2,L,Lr);
    		solve(mid+1,y1,x2,y2,Rl,R);
    	}
    	else {
    		int mid=(y1+y2)/2;
    		for (int i=x1;i<=x2;i++){
    			Dijkstra(HA(i,mid),x1,y1,x2,y2);
    			for (int j=L;j<=R;j++)
    				q[id[j]].ans=min(q[id[j]].ans,d[q[id[j]].s]+d[q[id[j]].t]);
    		}
    		int Lr=L-1,Rl=R+1;
    		for (int j=L;j<=R;j++){
    			int y3=q[id[j]].s%m+1,y4=q[id[j]].t%m+1;
    			if (y3<mid&&y4<mid)
    				tmp[++Lr]=id[j];
    			if (y3>mid&&y4>mid)
    				tmp[--Rl]=id[j];
    		}
    		for (int j=L;j<=Lr;j++)
    			id[j]=tmp[j];
    		for (int j=Rl;j<=R;j++)
    			id[j]=tmp[j];
    		solve(x1,y1,x2,mid-1,L,Lr);
    		solve(x1,mid+1,x2,y2,Rl,R);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	buildg();
    	scanf("%d",&Q);
    	for (int i=1;i<=Q;i++)
    		q[i].get(),id[i]=i;
    	solve(1,1,n,m,1,Q);
    	for (int i=1;i<=Q;i++)
    		printf("%d
    ",q[i].ans);
    	return 0;
    }
    

      

  • 相关阅读:
    如何开启无线网卡
    E-SATA接口
    sata express接口
    联想服务器驱动
    国家信息安全漏洞共享平台
    SQL SERVER 性能调优
    计算机网络知识库
    CCNP 视频
    ORACLE 培训 -相克军
    phxsql
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4456.html
Copyright © 2020-2023  润新知