• [BZOJ4456] [Zjoi2016]旅行者 分治+最短路


    4456: [Zjoi2016]旅行者

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 777  Solved: 439
    [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

    不想写题解了,发现BZOJ有题解,直接抄就完事了

     实际上分块和分治的思想是差不多的,就直接讲分治吧。。
    
           首先转离线操作,然后对于某一个矩形区间x∈[lx,rx],y∈[ly,ry],然后要求出所有源点和汇点都在其中的询问,且路径不超出所在区间的答案。不妨设rx-lx>ly-ty,那么对x坐标进行分治,即将这个区间分成两块,那么对于某一个询问,有两种情况:
    
           1.如果询问的起点和终点在两个不同的块,那么一定会经过中轴线上的一点;
    
           2.如果在同一块,那么有可能经过中轴线;也有可能路径只在那一块中,就可以递归分治了;
    
           那么对于某一块,求出中轴线到所在块的所有点的距离,更新一下答案;然后递归分治。
    
           考虑用dijkstra+heap跑最短路,那么就大概是O(N^1.5logN)的(因为思想和kd-tree是差不多的吧所以时间也一样)。本地测试后两个点dijkstra+heap的时间接近spfa的一半
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 #include<queue>
     6 #include<cmath>
     7 #include<algorithm>
     8 #define maxn 20105
     9 using namespace std;
    10 inline int read() {
    11     int x=0,f=1;char ch=getchar();
    12     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    13     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    14     return x*f;
    15 }
    16 
    17 struct Node {
    18     int x,y,d;
    19     bool operator <(const Node &tmp) const {return d>tmp.d;}
    20 };
    21 struct query {int x1,y1,x2,y2,id;}a[100005],L[100005],R[100006];
    22 int ans[100005];
    23 int v[maxn][4];
    24 int n,m,Q;
    25 int dis[maxn],vis[maxn];
    26 int tx[4]={1,-1,0,0},ty[4]={0,0,1,-1};
    27 priority_queue<Node> q;
    28 inline int get(int x,int y) {return (x-1)*m+y;}
    29 inline void dij(int x,int y,int x1,int x2,int y1,int y2) {
    30     for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) dis[get(i,j)]=1000000000,vis[get(i,j)]=0;
    31     q.push((Node){x,y,0});
    32     dis[get(x,y)]=0;
    33     while(!q.empty()) {
    34         Node now=q.top();q.pop();
    35         if(vis[get(now.x,now.y)]) continue;
    36         vis[get(now.x,now.y)]=1;
    37         for(int i=0;i<4;i++) {
    38             int tox=now.x+tx[i],toy=now.y+ty[i];
    39             if(tox>x2||tox<x1||toy>y2||toy<y1) continue;
    40             if(dis[get(tox,toy)]>dis[get(now.x,now.y)]+v[get(now.x,now.y)][i]) {
    41                 dis[get(tox,toy)]=dis[get(now.x,now.y)]+v[get(now.x,now.y)][i];
    42                 q.push((Node){tox,toy,dis[get(tox,toy)]});
    43                 
    44             }
    45         }
    46     }
    47 }
    48 inline void solve(int x1,int x2,int y1,int y2,int ql,int qr) {
    49     if(qr<ql) return;
    50     if(x1==x2&&y1==y2) {
    51         for(int i=ql;i<=qr;i++) ans[a[i].id]=0;
    52         return ;
    53     }
    54     if(x2-x1>y2-y1) {
    55         int mid=(x2+x1)>>1;
    56         for(int i=y1;i<=y2;i++) {
    57             dij(mid,i,x1,x2,y1,y2);
    58             for(int j=ql;j<=qr;j++) ans[a[j].id]=min(ans[a[j].id],dis[get(a[j].x1,a[j].y1)]+dis[get(a[j].x2,a[j].y2)]);
    59         }
    60         int l=0,r=0;
    61         for(int i=ql;i<=qr;i++) {
    62             if(a[i].x1<=mid&&a[i].x2<=mid) L[++l]=a[i];
    63             if(a[i].x1>mid&&a[i].x2>mid) R[++r]=a[i];
    64         }
    65         for(int i=1;i<=l;i++) a[ql+i-1]=L[i];
    66         for(int i=1;i<=r;i++) a[ql+l+i-1]=R[i];
    67         solve(x1,mid,y1,y2,ql,ql+l-1);solve(mid+1,x2,y1,y2,ql+l,ql+l+r-1);
    68     }
    69     else {
    70         int mid=(y2+y1)>>1;
    71         for(int i=x1;i<=x2;i++) {
    72             dij(i,mid,x1,x2,y1,y2);
    73             for(int j=ql;j<=qr;j++) ans[a[j].id]=min(ans[a[j].id],dis[get(a[j].x1,a[j].y1)]+dis[get(a[j].x2,a[j].y2)]);
    74             
    75         }
    76         int l=0,r=0;
    77         for(int i=ql;i<=qr;i++) {
    78             if(a[i].y1<=mid&&a[i].y2<=mid) L[++l]=a[i];
    79             if(a[i].y1>mid&&a[i].y2>mid) R[++r]=a[i];
    80         }
    81         for(int i=1;i<=l;i++) a[ql+i-1]=L[i];
    82         for(int i=1;i<=r;i++) a[ql+l+i-1]=R[i];
    83         solve(x1,x2,y1,mid,ql,ql+l-1);solve(x1,x2,mid+1,y2,ql+l,ql+l+r-1);
    84     }
    85 }
    86 int main() {
    87     memset(v,27,sizeof(v));
    88     n=read(),m=read();
    89     for(int i=1;i<=n;i++) for(int j=1;j<m;j++) v[get(i,j)][2]=v[get(i,j+1)][3]=read();
    90     for(int i=1;i<n;i++) for(int j=1;j<=m;j++) v[get(i,j)][0]=v[get(i+1,j)][1]=read();
    91     Q=read();
    92     for(int i=1;i<=Q;i++) {
    93         a[i].x1=read(),a[i].y1=read(),a[i].x2=read(),a[i].y2=read();
    94         a[i].id=i;ans[i]=2147483647;
    95     }
    96     solve(1,n,1,m,1,Q);
    97     for(int i=1;i<=Q;i++) printf("%d
    ",ans[i]);
    98 }
    View Code
  • 相关阅读:
    蚂蚁金服井贤栋:用技术联手金融机构,形成服务小微的生态合力
    蚂蚁金服 Service Mesh 渐进式迁移方案|Service Mesh Meetup 实录
    蚂蚁金服“定损宝”现身AI顶级会议NeurIPS
    报名 | 蚂蚁金服ATEC科技大会 · 上海:数字金融新原力
    前沿 | 中国中小银行都是如何展开数字化转型的?
    盘点:2018年双11背后的蚂蚁核心技术
    构筑敏捷能力中心,打造下一代数字银行“操作系统”!
    客户故事:4家银行如何打造新一代移动金融中心
    干货 | 金融级互联网产品持续交付的挑战与应对
    性能跃升50%!解密自主研发的金融级分布式关系数据库OceanBase 2.0
  • 原文地址:https://www.cnblogs.com/wls001/p/9754984.html
Copyright © 2020-2023  润新知