zoukankan      html  css  js  c++  java
  • 【ZJOI2016】旅行者

    【ZJOI2016】旅行者

    题意:

    给你一个网格图以及图上的边权,多个询问,求网格图内两点的最短路径。点数不多于 $ 20000 $ ,询问不超过 $ 100000 $ ,边权不超过 $ 10000 $ 。

    题解:

    算法一:

    对于每次询问暴力跑两点最短路,听说是网格图, $ Spfa $ 再见, $ Dijkstra $ 加堆优化飞起。得分 $ 20 $ 。

    算法二:

    在线做法已经很难再快了,考虑离线。这是一个网格图,所以我们考虑分治,每次处理左上端点为 $ (x1, y1) $ 右下端点为 $ (x2, y2) $ 矩形且询问的点都在范围内的询问。然后我们要将这个矩形切开,当然最好是从中间切开。然后我们考虑当前所有询问经过中线的答案是否比当前答案更优,然后将询问分类并进行分治(跨过中线的两个点答案已经算好,其他的还需递归分治)。我们发现将矩形较长边从中间切开较优。时间复杂度玄学(听说是 $ O(n sqrt{n} log{n}) $ 的)。
    咦,被卡常了?得分 $ 50 $ ~ $ 100 $ 分。

    算法三:

    考虑剪枝。如果当前矩形内询问只有一两个时直接暴力查询即可,其实也没快多少

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=20010,M=100010,INF=2e9;
    const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
    int n,m,k,e[N][4];
    struct Q { int l1,r1,l2,r2,id; }; Q q[M],ta[M],tb[M];
    int ans[M],dis[N];
    struct D {
    	int id,w; D(int Id=0,int W=0):id(Id),w(W) {}
    	inline bool operator<(const D &yy)const { return w>yy.w; }
    };priority_queue <D> h;
    
    int read() {
    	register int tmp=0;register char c=getchar();
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';tmp=(tmp<<1)+(tmp<<3)+(c^48),c=getchar());
    	return tmp;
    }
    inline int Min(int x,int y) { return x<y? x:y; }
    inline int g(int x,int y) { return (x-1)*m+y; }
    void Dijkstra(int l1,int r1,int l2,int r2,int s) {
    	for(int i=l1;i<=l2;i++) for(int j=r1;j<=r2;j++) dis[g(i,j)]=INF;
    	dis[s]=0,h.push(D(s,0));
    	for(;!h.empty();) {
    		D u=h.top(); h.pop(); if(u.w!=dis[u.id]) continue;
    		int x=(u.id-1)/m+1,y=(u.id-1)%m+1,tx,ty,w;
    		for(int i=0;i<4;i++) {
    			tx=x+dir[i][0],ty=y+dir[i][1],w=e[u.id][i];
    			if(tx<l1||tx>l2||ty<r1||ty>r2) continue;
    			if(dis[g(tx,ty)]>u.w+w)
    				dis[g(tx,ty)]=u.w+w,h.push(D(g(tx,ty),dis[g(tx,ty)]));
    		}
    	}
    }
    void solve(int l1,int r1,int l2,int r2,int l,int r) {
    	if(l1>l2||r1>r2||l>r) return ;
    	if(l==r) {
    		Dijkstra(l1,r1,l2,r2,g(q[l].l1,q[l].r1));
    		ans[q[l].id]=Min(dis[g(q[l].l2,q[l].r2)],ans[q[l].id]); return ;
    	}
    	if(l2-l1<=r2-r1) {
    		int mid=(r1+r2)/2;
    		for(int i=l1;i<=l2;i++) {
    			Dijkstra(l1,r1,l2,r2,g(i,mid));
    			for(int j=l;j<=r;j++)
    				ans[q[j].id]=Min(ans[q[j].id],
    				dis[g(q[j].l1,q[j].r1)]+dis[g(q[j].l2,q[j].r2)]);
    		}
    		int la=0,lb=0;
    		for(int i=l;i<=r;i++) {
    			if(q[i].r1<=mid&&q[i].r2<=mid) ta[++la]=q[i];
    			if(q[i].r1>mid&&q[i].r2>mid) tb[++lb]=q[i];
    		}
    		for(int i=1;i<=la;i++) q[i+l-1]=ta[i];
    		for(int i=1;i<=lb;i++) q[r-i+1]=tb[i];
    		if(r1==r2) return ;
    		solve(l1,r1,l2,mid,l,l+la-1),solve(l1,mid+1,l2,r2,r-lb+1,r);
    	}
    	else {
    		int mid=(l1+l2)/2;
    		for(int i=r1;i<=r2;i++) {
    			Dijkstra(l1,r1,l2,r2,g(mid,i));
    			for(int j=l;j<=r;j++)
    				ans[q[j].id]=Min(ans[q[j].id],
    				dis[g(q[j].l1,q[j].r1)]+dis[g(q[j].l2,q[j].r2)]);
    		}
    		int la=0,lb=0;
    		for(int i=l;i<=r;i++) {
    			if(q[i].l1<=mid&&q[i].l2<=mid) ta[++la]=q[i];
    			if(q[i].l1>mid&&q[i].l2>mid) tb[++lb]=q[i];
    		}
    		for(int i=1;i<=la;i++) q[i+l-1]=ta[i];
    		for(int i=1;i<=lb;i++) q[r-i+1]=tb[i];
    		if(l1==l2) return ;
    		solve(l1,r1,mid,r2,l,l+la-1),solve(mid+1,r1,l2,r2,r-lb+1,r);
    	}
    }
    int main() {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<m;j++) e[g(i,j)][1]=e[g(i,j+1)][3]=read();
    	for(int i=1;i<n;i++)
    		for(int j=1;j<=m;j++) e[g(i,j)][0]=e[g(i+1,j)][2]=read();
    	k=read();
    	for(int i=1;i<=k;i++) {
    		q[i].id=i,ans[i]=INF;
    		q[i].l1=read(),q[i].r1=read(),q[i].l2=read(),q[i].r2=read();
    	}
    	solve(1,1,n,m,1,k); for(int i=1;i<=k;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET教程4
    ASP.NET教程11
    TreeView Demo
    System.Net.Dns.GetHostByAddress(string) 已经过时
    会员注册实例
    ASP.NET教程2
    多表关联与表值函数
    ASP.NET教程6
    BusinessFrameWork
    ASP.NET教程8
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10322757.html
Copyright © 2011-2022 走看看