zoukankan      html  css  js  c++  java
  • 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("
    ")
     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
    View Code
  • 相关阅读:
    测试一下你的T-SQL基础知识-count
    测试一下你的T-SQL基础知识-subquery
    Microsoft SQL Server 2012 管理 (2): Auditing
    Webpack
    react
    Webpack 傻瓜式指南(一)
    谈谈react-router学习
    使用Flexible 实现手淘H5 页面的终端适配学习
    Promise 让异步更优
    基于LeanCloud云引擎的Web全栈方案
  • 原文地址:https://www.cnblogs.com/GhostReach/p/6492191.html
Copyright © 2011-2022 走看看