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
2
3
6 4
2
1 1 2 2
1 2 2 1
Sample Output
6
7
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(" ") 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!=' ' 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 ",ans[i]); 154 end