zoukankan      html  css  js  c++  java
  • bzoj4456 [Zjoi2016]旅行者

    4456: [Zjoi2016]旅行者

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 651  Solved: 375
    [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
    n*m ≤ 2×10^4
    q ≤ 10^5
    相邻路口时间不超过10^4
    分析:idea很妙的一道题.
       和棋盘迷宫这道题的想法差不多. 多组询问,要么一组一组地快速处理,要么像整体二分一样一下子全部处理完.  这道题采用平面内分治的方法来回答所有询问.
       画一条中线. 询问的两个点都在中线同一侧的询问,会在以后的递归中处理. 考虑两个点在中线异侧的询问. 这两个点之间的路径一定经过会经过中线上的两个点(这两个点可能重合).那么以中线上的每一个点为源点做dijkstra,用到达两个点的路径长度和去更新答案即可.
       那么中线是哪一条线呢?(到底是分治x还是分治y呢?)
       显然分治越大的越好,因为要枚举中线上的点. 如果x大,就分治x,y大就分治y.
       注意,这道题卡常数!几个小小的优化:
       1.dijkstra的vis数组用时间戳优化。
       2.如果dijkstra松弛操作的点在当前分治层的边界之外了,就不要去松弛它.
       3.数组开小点,memset就会快点.
       再来看一看这道题和棋盘迷宫有什么相似点:
       1.平面图(边与边的交点只会在顶点上,这样可以分治)
       2.多组询问,支持离线.
       3.询问的是路径.
       通用的解法是分治中线,求这条中线上的所有点到询问的点对之间的答案.
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 500010;
    int n,m,ans[maxn],Q,d[20010],head[maxn],to[maxn],nextt[maxn],tot = 1,w[maxn],idx[maxn],idy[maxn],vis[maxn],Tim;
    
    struct node
    {
        int x3,y3,x4,y4,x,y,id;
    } e[maxn],p[maxn];
    
    struct node2
    {
        int len,x;
        bool operator < (const node2 &b) const
        {
            return len > b.len;
        }
    };
    
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    void add(int x,int y,int z)
    {
        w[tot] = z;
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    int id(int x,int y)
    {
        return (x - 1) * m + y;
    }
    
    void dijkstra(int S,int x3,int y3,int x4,int y4)
    {
        priority_queue <node2> q;
        Tim++;
        node2 temp;
        temp.x = S;
        temp.len = 0;
        q.push(temp);
        memset(d,127/3,sizeof(d));
        d[S] = 0;
        while (!q.empty())
        {
            node2 u = q.top();
            q.pop();
            if (vis[u.x] == Tim)
                continue;
            vis[u.x] = Tim;
            for (int i = head[u.x]; i; i = nextt[i])
            {
                int v = to[i];
                if (idx[v] < x3 || idx[v] > x4 || idy[v] < y3 || idy[v] > y4)
                    continue;
                if (d[v] > d[u.x] + w[i])
                {
                    d[v] = d[u.x] + w[i];
                    node2 temp;
                    temp.x = v;
                    temp.len = d[v];
                    q.push(temp);
                }
            }
        }
    }
    
    void solve(int x3,int y3,int x4,int y4,int ql,int qr)
    {
        if (x3 > x4 || y3 > y4 || ql > qr)
            return;
        if (x4 - x3 <= y4 - y3)
        {
            int mid = (y3 + y4) >> 1;
            int L = ql - 1,R = qr + 1;
            for (int i = ql; i <= qr; i++)
            {
                if (e[i].y3 < mid && e[i].y4 < mid)
                    p[++L] = e[i];
                else if (e[i].y3 > mid && e[i].y4 > mid)
                    p[--R] = e[i];
            }
            for (int i = x3; i <= x4; i++)
            {
                dijkstra(id(i,mid),x3,y3,x4,y4);
                for (int j = ql; j <= qr; j++)
                    ans[e[j].id] = min(ans[e[j].id],d[e[j].x] + d[e[j].y]);
            }
            for (int i = ql; i <= L; i++)
                e[i] = p[i];
            for (int i = R; i <= qr; i++)
                e[i] = p[i];
            solve(x3,y3,x4,mid - 1,ql,L);
            solve(x3,mid + 1,x4,y4,R,qr);
        }
        else
        {
            int mid = (x3 + x4) >> 1;
            int L = ql - 1,R = qr + 1;
            for (int i = ql; i <= qr; i++)
            {
                if (e[i].x3 < mid && e[i].x4 < mid)
                    p[++L] = e[i];
                if (e[i].x3 > mid && e[i].x4 > mid)
                    p[--R] = e[i];
            }
            for (int i = y3; i <= y4; i++)
            {
                dijkstra(id(mid,i),x3,y3,x4,y4);
                for (int j = ql; j <= qr; j++)
                    ans[e[j].id] = min(ans[e[j].id],d[e[j].x] + d[e[j].y]);
            }
            for (int i = ql; i <= L; i++)
                e[i] = p[i];
            for (int i = R; i <= qr; i++)
                e[i] = p[i];
            solve(x3,y3,mid - 1,y4,ql,L);
            solve(mid + 1,y3,x4,y4,R,qr);
        }
    }
    
    int main()
    {
        memset(ans,127/3,sizeof(ans));
        n = read(),m = read();
        for (int i = 1; i <= n; i++)
            for (int j = 1; j < m; j++)
            {
                int t;
                t = read();
                add(id(i,j),id(i,j + 1),t);
                add(id(i,j + 1),id(i,j),t);
            }
        for (int i = 1; i < n; i++)
            for (int j = 1; j <= m; j++)
            {
                int t;
                t = read();
                add(id(i,j),id(i + 1,j),t);
                add(id(i + 1,j),id(i,j),t);
            }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                int t = id(i,j);
                idx[t] = i;
                idy[t] = j;
            }
        Q = read();
        for (int i = 1; i <= Q; i++)
        {
            e[i].x3 = read(),e[i].y3 = read(),e[i].x4 = read(),e[i].y4 = read();
            e[i].x = id(e[i].x3,e[i].y3);
            e[i].y = id(e[i].x4,e[i].y4);
            e[i].id = i;
        }
        solve(1,1,n,m,1,Q);
        for (int i = 1; i <= Q; i++)
            printf("%d
    ",ans[i]);
    
        return 0;
    }
  • 相关阅读:
    【3006】统计数字
    【5001】n皇后问题
    【7001】n阶法雷序列
    【9402】倒序数
    【9705】&&【a801】细胞
    【9802】闭合曲线面积
    【a803】营救
    【9112】求2的n次方的精确值
    V8引擎实现标准ECMA-262(三)
    仔细看看Javascript中的逻辑与(&&)和逻辑或(||)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8698847.html
Copyright © 2011-2022 走看看