您的位置:首页 > 其它

4456: [Zjoi2016]旅行者

2016-12-21 13:21 656 查看

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

 题解:JudgeOnline/upload/201603/4456 sol.txt

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: