BZOJ4456:[ZJOI2016]旅行者

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
 
题解:
奇妙的平面网格图分治做法。
假设现在分治到了一个矩形范围,并在中间找到了一条横或竖的分割线。将起点到终点都在矩形范围内的询问记为当前询问。
考虑当前询问的只经过这个大矩形中的点、但是不能只经过其中半个矩形的点的最短路径,则必定经过矩形的分割线。
将分割线上的每个点跑一次这个大矩形范围的dijkstra+堆优化,对于当前每个询问,枚举最短路径经过了分割线上的哪个点,更新答案。
将这个矩形沿分割线分为两个小矩形(不包括分割线),把相应的当前询问下传。
注意选择分割线时应该把较长的矩形边分为两半。
 
代码(P++注意):
  1 #include<bits/stdc++.h>
  2 #define begin {
  3 #define end }
  4 #define while while(
  5 #define if if(
  6 #define do )
  7 #define then )
  8 #define for for(
  9 #define fillchar(a,b,c) memset(a,c,b)
 10 #define writeln printf("\n")
 11 #define write printf
 12 #define readln readl()
 13 #define inc(a) a++
 14 #define dec(a) a--
 15 #define exit(a) return a
 16 #define mod %
 17 #define div /
 18 #define shl <<
 19 #define shr >>
 20 #define extended long double
 21 #define longint int
 22 #define integer short
 23 #define int64 long long
 24 template<typename T> inline void read(T& a)
 25 begin
 26   T x=0,f=1; char ch=getchar();
 27   while(ch<'0')or(ch>'9')do
 28   begin
 29     if ch=='-' then f=-1; ch=getchar();
 30   end
 31   while(ch>='0')and(ch<='9')do
 32   begin
 33     x=x*10+ch-'0'; ch=getchar();
 34   end
 35   a=x*f;
 36 end
 37 using namespace std;
 38 inline void readl()
 39 begin
 40   char ch; ch=getchar();
 41   while ch!='\n' do ch=getchar();
 42 end
 43 int dis[200005],dis2[200005],tp[200005],f[200005],v[200005],i,j,k,n,m,cnt,w[100005];
 44 int r[200005],c[200005],q[100005][5],a[100005],qq,ans[100005];
 45 const int fx[4]={-1,0,1,0};
 46 const int fy[4]={0,-1,0,1};
 47 inline void up(int x)
 48 begin
 49   int t,i;
 50   while x>1 do
 51   begin
 52     i=x div 2;
 53     if dis[tp[x]]<dis[tp[i]] then
 54     begin swap(tp[i],tp[x]); w[tp[x]]=x; w[tp[i]]=i; x=i; end else break;
 55   end
 56 end
 57 inline void down(int x)
 58 begin
 59   int t,i,j;
 60   while true do
 61   begin
 62     i=x*2; j=i+1;
 63     if(j<=cnt)and(dis[tp[j]]<dis[tp[i]])then i=j;
 64     if(i<=cnt)and(dis[tp[i]]<dis[tp[x]])then
 65     begin swap(tp[x],tp[i]); w[tp[x]]=x; w[tp[i]]=i; x=i; end else break;
 66   end
 67 end    
 68 inline void dij(int x,int y,int ll1,int rr1,int ll2,int rr2)
 69 begin
 70   cnt=0; int k,xx,yy,xxx,yyy,disk,mu,jia,tot=0;
 71   int i,j;
 72   for i=ll1;i<=rr1;i++ do
 73   for j=ll2;j<=rr2;j++ do
 74   begin
 75     inc(tot);
 76     mu=m*(i-1)+j-1; v[mu]=0; 
 77     if(i==x)and(j==y)then dis[mu]=0,inc(cnt),tp[cnt]=mu,w[mu]=cnt,up(cnt);
 78     else dis[mu]=1000000000;
 79   end
 80   for i=1;i<=tot;i++ do
 81   begin
 82     k=tp[1]; v[k]=1; disk=dis[k]; dis2[k]=dis[k]; dis[k]=2000000000; down(1); xx=k div m+1; yy=k mod m+1;
 83     for j=0;j<=3;j++ do
 84     if(xx+fx[j]>=ll1)and(xx+fx[j]<=rr1)and(yy+fy[j]>=ll2)and(yy+fy[j]<=rr2)then
 85     begin
 86       xxx=xx+fx[j]; yyy=yy+fy[j]; mu=m*(xxx-1)+yyy-1; if v[mu]==1 then continue;
 87       if j==0 then jia=c[mu];else if j==1 then jia=r[mu];else
 88       if j==2 then jia=c[mu-m];else jia=r[mu-1];
 89       if disk+jia<dis[mu] then
 90       begin 
 91         if dis[mu]==1000000000 then inc(cnt),tp[cnt]=mu,w[mu]=cnt;
 92         dis[mu]=disk+jia; up(w[mu]);
 93       end
 94     end
 95   end
 96 end
 97 inline bool in(int x,int l1,int r1,int l2,int r2)
 98 begin
 99   exit((q[x][1]>=l1)and(q[x][1]<=r1)and(q[x][2]>=l2)and(q[x][2]<=r2)and(q[x][3]>=l1)and(q[x][3]<=r1)and(q[x][4]>=l2)and(q[x][4]<=r2));
100 end
101 void ss(int l1,int r1,int l2,int r2,int ql,int qr)
102 begin
103   if(l1>r1)or(l2>r2)or(ql>qr)then return;
104   int i=ql,j=qr,l3=l1,r3=r1,l4=l2,r4=r2,l5=l1,r5=r1,l6=l2,r6=r2,x,midx,t,ii,jj;
105   if(r2-l2>r1-l1)then begin x=2; midx=(r2+l2)div 2; r4=midx-1; l6=midx+1; end
106   else begin x=1; midx=(r1+l1)div 2; r3=midx-1; l5=midx+1; end
107   while i<=j do
108   begin
109     while(i<=qr)and((in(a[i],l3,r3,l4,r4))or(in(a[i],l5,r5,l6,r6)))do i++;
110     while(j>=ql)and(not((in(a[j],l3,r3,l4,r4))or(in(a[j],l5,r5,l6,r6))))do j--;
111     if i<=j then
112     begin swap(a[i],a[j]); i++; j--; end
113   end
114   if x==1 then 
115   begin
116     for ii=l2;ii<=r2;ii++ do  
117     begin
118       dij(midx,ii,l1,r1,l2,r2);
119       for jj=ql;jj<=qr;jj++ do 
120       ans[a[jj]]=min(ans[a[jj]],dis2[m*(q[a[jj]][1]-1)+q[a[jj]][2]-1]+dis2[m*(q[a[jj]][3]-1)+q[a[jj]][4]-1]);
121     end
122   end else  
123   begin
124     for ii=l1;ii<=r1;ii++ do  
125     begin
126       dij(ii,midx,l1,r1,l2,r2);
127       for jj=ql;jj<=qr;jj++ do 
128       ans[a[jj]]=min(ans[a[jj]],dis2[m*(q[a[jj]][1]-1)+q[a[jj]][2]-1]+dis2[m*(q[a[jj]][3]-1)+q[a[jj]][4]-1]);
129     end
130   end
131   qr=i-1; if ql>qr then return;
132   i=ql; j=qr;
133   while i<=j do
134   begin
135     while(i<=qr)and(in(a[i],l3,r3,l4,r4))do i++;
136     while(j>=ql)and(in(a[j],l5,r5,l6,r6))do j--;
137     if i<=j then
138     begin swap(a[i],a[j]); i++; j--; end
139   end
140   if i<=qr then ss(l5,r5,l6,r6,i,qr);
141   if j>=ql then ss(l3,r3,l4,r4,ql,j);
142 end
143 int main()
144 begin
145   read(n); read(m);
146   for i=1;i<=n;i++ do
147   for j=1;j<=m-1;j++ do read(r[m*(i-1)+j-1]);
148   for i=1;i<=n-1;i++ do
149   for j=1;j<=m;j++ do read(c[m*(i-1)+j-1]);
150   read(qq);
151   for i=1;i<=qq;i++ do begin read(q[i][1]); read(q[i][2]); read(q[i][3]); read(q[i][4]); a[i]=i; ans[i]=2000000000; end
152   ss(1,n,1,m,1,qq);
153   for i=1;i<=qq;i++ do write("%d\n",ans[i]);
154 end
View Code
posted @ 2017-03-02 19:34  GhoStreach  阅读(247)  评论(0编辑  收藏  举报