4456: [Zjoi2016]旅行者

7 篇文章 0 订阅
6 篇文章 0 订阅

4456: [Zjoi2016]旅行者

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 284   Solved: 174
[ Submit][ Status][ Discuss]

Description

小Y来到了一个新的城市旅行。她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北
的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m)。她发现不同的道路路况不同,所以通过不
同的路口需要不同的时间。通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1
,j)需要时间c(i,j)。注意这里的道路是双向的。小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要
花多少时间。

Input

第一行包含 2 个正整数n,m,表示城市的大小。
接下来n行,每行包含m?1个整数,第i行第j个正整数表示从一个路口到另一个路口的时间r(i,j)。
接下来n?1行,每行包含m个整数,第i行第j个正整数表示从一个路口到另一个路口的时间c(i,j)。
接下来一行,包含1个正整数q,表示小Y的询问个数。
接下来q行,每行包含4个正整数 x1,y1,x2,y2,表示两个路口的位置。

Output

输出共q行,每行包含一个整数表示从一个路口到另一个路口最少需要花的时间。

Sample Input

2 2
2
3
6 4
2
1 1 2 2
1 2 2 1

Sample Output

6
7

HINT

Source

[ Submit][ Status][ Discuss]



分治 + 最短路解决

一开始拿到一个矩形,要在上面回答Q次两点间的最短路

可以找到矩形的长,选取中轴,如果两点跨越这条线,那么最短路必经该线上一点

否则最短路只是可能经过该轴上一个点

那就把中轴线上每个点拿出来做一次Dijkstra,更新所有询问答案

然后将询问分类,两点都在中轴一侧的递归下去,否则它的最短路已经统计完了

就是利用分治的思想。。。。。

记得每次要选长和宽较大的二分

O(n^(1.5)logn + q*n^(0.5)logn)常数巨大= =

卡了一早上常数。。。。。。。。。。。。。。

分治向下转移的时候,一开始用的动态数组。。舍去了

然后是堆。。用了pbds的配对堆。。。O(nlogn),,比普通堆略快一点

最后压着时限过的= =

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 2E4 + 20;
const int maxm = 1E5 + 10;
const int INF = ~0U>>1;

struct E{
	int to,w; E(){}
	E(int to,int w): to(to),w(w){}
};

struct data{
	int Dis,num; data(){}
	data(int Dis,int num): Dis(Dis),num(num){}
	bool operator < (const data &b) const {return Dis > b.Dis;}
};
typedef __gnu_pbds::priority_queue<data,less<data>,__gnu_pbds::pairing_heap_tag> Heap;

int n,m,q,cnt,Cnt,tp,dis[maxn],vis[maxn],h[maxm],h1[maxm]
	,h2[maxm],ans[maxm],r1[maxm],c1[maxm],r2[maxm],c2[maxm]
	,End[maxn],from[maxn*4],to[maxn*4],w[maxn*4],stk[maxn];
bool inq[maxn];
	
Heap Q; Heap::point_iterator id[maxn];

int Get(const int &x,const int &y) {return (x-1)*m + y;}
int Get_n(const int &Num) {return (Num % m == 0)?Num / m:Num / m + 1;}
int Get_m(const int &Num) {return (Num % m == 0)?m:Num % m;}

void Dijkstra(int x,int ln,int rn,int lm,int rm)
{
	id[x] = Q.push(data(0,x)); dis[x] = 0; 
	inq[x] = 1; stk[tp = 1] = x;
	while (!Q.empty())
	{
		int k = Q.top().num; Q.pop();
		for (int i = End[k]; i; i = from[i])
		{
			int N = Get_n(to[i]),M = Get_m(to[i]);
			if (N < ln || rn < N || M < lm || rm < M) continue;
			if (dis[to[i]] > dis[k] + w[i])
			{
				dis[to[i]] = dis[k] + w[i];
				if (!inq[to[i]]) 
					inq[to[i]] = 1,id[to[i]] = Q.push(data(dis[to[i]],to[i])),stk[++tp] = to[i];
				else Q.modify(id[to[i]],data(dis[to[i]],to[i]));
			}
		}
	}
}

void Solve(int ln,int rn,int lm,int rm,int L,int R)
{
	if (rn - ln < rm - lm)
	{
		int mid = (lm + rm) >> 1;
		for (int i = ln; i <= rn; i++)
		{
			Dijkstra(Get(i,mid),ln,rn,lm,rm);
			for (int j = L; j <= R; j++)
			{
				int Now = h[j];
				int A = Get(r1[Now],c1[Now]);
				int B = Get(r2[Now],c2[Now]);
				ans[Now] = min(ans[Now],dis[A] + dis[B]);
			}
			while (tp) {inq[stk[tp]] = 0; dis[stk[tp]] = INF; --tp;}
		}
		if (lm == rm) return;
		int tpl,tpr; tpl = tpr = 0;
		for (int i = L; i <= R; i++)
		{
			int Now = h[i],A = min(c1[Now],c2[Now]),B = max(c1[Now],c2[Now]);
			if (A <= mid && mid < B) continue;
			if (B <= mid) h1[++tpl] = Now; else h2[++tpr] = Now;
		}
		for (int i = 1; i <= tpl; i++) h[L+i-1] = h1[i];
		for (int i = 1; i <= tpr; i++) h[L+tpl+i-1] = h2[i];
		if (tpl) Solve(ln,rn,lm,mid,L,L+tpl-1);
		if (tpr) Solve(ln,rn,mid+1,rm,L+tpl,L+tpl+tpr-1);
	}
	else
	{
		int mid = (ln + rn) >> 1;
		for (int i = lm; i <= rm; i++)
		{
			Dijkstra(Get(mid,i),ln,rn,lm,rm);
			for (int j = L; j <= R; j++)
			{
				int Now = h[j];
				int A = Get(r1[Now],c1[Now]);
				int B = Get(r2[Now],c2[Now]);
				ans[Now] = min(ans[Now],dis[A] + dis[B]);
			}
			while (tp) {inq[stk[tp]] = 0; dis[stk[tp]] = INF; --tp;}
		}
		if (ln == rn) return;
		int tpl,tpr; tpl = tpr = 0;
		for (int i = L; i <= R; i++)
		{
			int Now = h[i],A = min(r1[Now],r2[Now]),B = max(r1[Now],r2[Now]);
			if (A <= mid && mid < B) continue;
			if (B <= mid) h1[++tpl] = Now; else h2[++tpr] = Now;
		}
		for (int i = 1; i <= tpl; i++) h[L+i-1] = h1[i];
		for (int i = 1; i <= tpr; i++) h[L+tpl+i-1] = h2[i];
		if (tpl) Solve(ln,mid,lm,rm,L,L+tpl-1);
		if (tpr) Solve(mid+1,rn,lm,rm,L+tpl,L+tpl+tpr-1);
	}
}

void Add_edgs(int x,int y,int z)
{
	from[++Cnt] = End[x]; End[x] = Cnt; 
	to[Cnt] = y; w[Cnt] = z;
}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#else
		freopen("4456.in","r",stdin);
		freopen("4456.out","w",stdout);
	#endif
	
	n = getint(); m = getint();
	for (int i = 1; i <= n; i++)
		for (int j = 1; j < m; j++)
		{
			int x = getint();
			Add_edgs(Get(i,j),Get(i,j+1),x);
			Add_edgs(Get(i,j+1),Get(i,j),x);
		}
	for (int i = 1; i < n; i++)
		for (int j = 1; j <= m; j++)
		{
			int x = getint();
			Add_edgs(Get(i,j),Get(i+1,j),x);
			Add_edgs(Get(i+1,j),Get(i,j),x);
		}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) dis[Get(i,j)] = INF;
	q = getint();
	for (int i = 1; i <= q; i++)
	{
		r1[i] = getint(); c1[i] = getint();
		r2[i] = getint(); c2[i] = getint();
		ans[i] = INF;
	}
	for (int i = 1; i <= q; i++) h[i] = i; 
	Solve(1,n,1,m,1,q);
	for (int i = 1; i <= q; i++) printf("%d\n",ans[i]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值