• 【BZOJ4456】旅行者(最短路,分治)


    【BZOJ4456】旅行者(最短路,分治)

    题面

    BZOJ

    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

    题解

    (ZJOI)上讲得题目
    感觉很有意思

    每次处理当前矩阵内的询问
    (x,y)两轴中较长的分成两半,使得矩阵尽可能“方”
    如果一个询问的两个点跨越了这个中线,
    则意味着答案一定经过了中线上的某个点
    于是对中线上每个点跑一边对短路,
    暴力更新答案
    复杂度不会证明

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 111111
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    const int inf=100000000;
    int n,m,Q;
    int dis[MAX];
    int X[MAX],Y[MAX],ans[MAX];
    bool vis[MAX];
    int bh(int i,int j){return i*m+j-m;}
    struct Line{int v,next,w;}e[200000];
    int h[MAX],cnt=1;
    inline void Add(int u,int v,int w)
    {
        e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
        e[cnt]=(Line){u,h[v],w};h[v]=cnt++;
    }
    struct Node{int i,dis;};
    bool operator<(Node a,Node b){return a.dis>b.dis;}
    void Dijkstra(int S,int lx,int ly,int rx,int ry)
    {
        priority_queue<Node> Q;
        Q.push((Node){S,0});
        for(int i=lx;i<=rx;++i)
            for(int j=ly;j<=ry;++j)
                dis[bh(i,j)]=inf,vis[bh(i,j)]=false;
        while(!Q.empty())
        {
            int u=Q.top().i,D=Q.top().dis;Q.pop();
            if(vis[u])continue;vis[u]=true;
            dis[u]=D;
            for(int i=h[u];i;i=e[i].next)
            {
                int v=e[i].v;
                if(!vis[v]&&lx<=X[v]&&X[v]<=rx&&ly<=Y[v]&&Y[v]<=ry)
                    Q.push((Node){v,dis[u]+e[i].w});
            }
        }
    }
    struct Query{int id,u,v;}q[MAX],tmp[MAX];
    void Work(int lx,int rx,int ly,int ry,int L,int R)
    {
        if(L>R)return;
        if(rx-lx>ry-ly)
        {
            int mid=(lx+rx)>>1;
            for(int i=ly;i<=ry;++i)
            {
                Dijkstra(bh(mid,i),lx,ly,rx,ry);
                for(int j=L;j<=R;++j)
                    ans[q[j].id]=min(ans[q[j].id],dis[q[j].u]+dis[q[j].v]);
            }
            int cntl=L-1,cntr=R+1;
            for(int i=L;i<=R;++i)
            {
                int u=q[i].u,v=q[i].v;
                if(X[u]<mid&&X[v]<mid)tmp[++cntl]=q[i];
                if(X[u]>mid&&X[v]>mid)tmp[--cntr]=q[i];
            }
            for(int i=L;i<=R;++i)q[i]=tmp[i];
            Work(lx,mid-1,ly,ry,L,cntl);
            Work(mid+1,rx,ly,ry,cntr,R);
        }
        else
        {
            int mid=(ly+ry)>>1;
            for(int i=lx;i<=rx;++i)
            {
                Dijkstra(bh(i,mid),lx,ly,rx,ry);
                for(int j=L;j<=R;++j)
                    ans[q[j].id]=min(ans[q[j].id],dis[q[j].u]+dis[q[j].v]);
            }
            int cntl=L-1,cntr=R+1;
            for(int i=L;i<=R;++i)
            {
                int u=q[i].u,v=q[i].v;
                if(Y[u]<mid&&Y[v]<mid)tmp[++cntl]=q[i];
                if(Y[u]>mid&&Y[v]>mid)tmp[--cntr]=q[i];	
            }
            for(int i=L;i<=R;++i)q[i]=tmp[i];
            Work(lx,rx,ly,mid-1,L,cntl);
            Work(lx,rx,mid+1,ry,cntr,R);
        }
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                X[bh(i,j)]=i,Y[bh(i,j)]=j;
        for(int i=1;i<=n;++i)
            for(int j=1;j<m;++j)
                Add(bh(i,j),bh(i,j+1),read());
        for(int i=1;i<n;++i)
            for(int j=1;j<=m;++j)
                Add(bh(i,j),bh(i+1,j),read());
        Q=read();
        for(int i=1;i<=Q;++i)
        {
            int xa=read(),ya=read(),xb=read(),yb=read();
            q[i]=(Query){i,bh(xa,ya),bh(xb,yb)};
        }
        memset(ans,63,sizeof(ans));
        Work(1,n,1,m,1,Q);
        for(int i=1;i<=Q;++i)printf("%d
    ",ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    小写数字转化为大写工具类
    java中关于日期类Calendar的简单使用
    ArrayList用法总结
    滚动条(附:定时调用)
    百度Echarts的使用总结
    Datatables 使用总结
    字符串(String、StringBuffer、StringBuilder)
    sqlserver 脚本方式导出数据到excel
    前端面试
    数据库面试
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8638749.html
Copyright © 2020-2023  润新知