• bzoj4456: [Zjoi2016]旅行者


    题目链接

    bzoj4456: [Zjoi2016]旅行者

    题解

    网格图,对于图分治,每次从中间切垂直于长的那一边,
    对于切边上的点做最短路,合并在图两边的答案。
    有点卡常

    代码

     #include<queue> 
    #include<cctype> 
    #include<cstdio> 
    #include<vector> 
    #include<cstring> 
    #include<algorithm> 
    inline int read() { 
        int x = 0,f = 1; 
        char c = getchar(); 
        while(c < '0' || c > '9')c = getchar(); 
        while(c <= '9' && c >= '0') x = x * 10 + c - '0', c = getchar(); 
        return x * f; 
    } 
    #define rg register 
    const int maxn = 100005; 
    int n,m,tot = 0,ans[maxn]; 
    int X[maxn],Y[maxn]; 
    
    struct node { 
        int v,next,w; 
    } edge[20005 << 2]; 
    int head[maxn],num = 0; 
    inline void add_edge(int u,int v,int w)  { 
        edge[++ num].v = v;edge[num].w = w; edge[num].next = head[u];head[u] = num; 
        edge[++ num].v = u;edge[num].w = w; edge[num].next = head[v];head[v] = num; 
    } 
    inline int id(rg int a,rg int b){return (a - 1) * m + b; } 
    struct Question { 
        int x,y,x1,y1,id; 
    } q[maxn],p[maxn]; 
    
    int dis[maxn]; 
    #define mp std::make_pair
    #define pr std::pair<int,int> 
    bool vis[maxn]; 
    std::priority_queue<pr> Q; 
    void dij(int x,int limx,int limy,int limx1,int limy1) { 
        for(int i = 1;i <= n;++ i) for(int j = 1;j <= m;++ j) 
            vis[id(i,j)] = 0,dis[id(i,j)] = 0x3f3f3f3f; 
        dis[x] = 0; 
        Q.push(mp(0,x)); 
        while(!Q.empty()) { 
            int u = Q.top().second; Q.pop(); 
            if(vis[u]) continue; 
            vis[u] = true; 
            for(int i = head[u];i;i = edge[i].next) { 
                int v = edge[i].v; 
                if(dis[v] > dis[u] + edge[i].w && X[v] >= limx && X[v] <= limx1 && Y[v] <= limy1 && Y[v] >= limy)  
                    dis[v] = edge[i].w + dis[u],Q.push(mp(-dis[v],v));  
            } 
        } 
    } 
    
    void solve(int x,int y,int x1,int y1,int l,int r) { 
        if(l > r) return ; 
        if(x1 - x > y1 - y) { 
            int mid = x + x1 >> 1; 
            for(int i = y;i <= y1 ;++ i) { 
                dij(id(mid,i),x,y,x1,y1); 
                for(int j = l;j <= r;++ j) 
                    ans[q[j].id] = std::min(ans[q[j].id],dis[id(q[j].x,q[j].y)] + dis[id(q[j].x1,q[j].y1)]); 
                } 
            int L = l - 1,R = r + 1; 
            for(int i = l;i <= r;++ i) { 
                if(q[i].x < mid && q[i].x1 < mid)p[++ L] = q[i]; 
                else if(q[i].x > mid && q[i].x1 > mid) p[-- R] = q[i]; 		
            } 
            for(int i = l ;i <= L;++ i) q[i] = p[i]; 
            for(int i = R ;i <= r;++ i) q[i] = p[i]; 
            solve(x,y,mid - 1,y1,l,L); solve(mid + 1,y,x1,y1,R,r); 
        } else { 
            int mid = y + y1 >> 1; 
            for(int i = x;i <= x1 ;++ i) { 
                dij(id(i,mid),x,y,x1,y1); 
                for(int j = l;j <= r;++ j) 
                    ans[q[j].id] = std::min(ans[q[j].id],dis[id(q[j].x,q[j].y)] + dis[id(q[j].x1,q[j].y1)]); 
                } 
            int L = l - 1,R = r + 1; 
            for(int i = l;i <= r;++ i) { 
                if(q[i].y < mid && q[i].y1 < mid)p[++ L] = q[i]; 
                else if(q[i].y > mid && q[i].y1 > mid) p[-- R] = q[i]; 		
            } 
            for(int i = l ;i <= L;++ i) q[i] = p[i]; 
            for(int i = R ;i <= r;++ i) q[i] = p[i]; 
            solve(x,y,x1,mid - 1,l,L); solve(x,mid + 1,x1,y1,R,r); 
        } 
    } 
    int main() { 
        //freopen("6.in","r",stdin); 
        n = read(), m = read(); 
        for(int i = 1;i <= n;++ i) for(int j = 1;j < m;++ j) 
            add_edge(id(i,j),id(i,j + 1),read()); 
        for(int i = 1;i < n;++ i) for(int j = 1;j <= m;++ j)  
            add_edge(id(i,j),id(i + 1,j),read()); 
        for(int i = 1;i <= n;++ i) for(int j = 1;j <= m;++ j) X[id(i,j)] = i,Y[id(i,j)] = j; 
        int T = read(); 
        while(T --) { 
            Question &a = q[++ tot]; 
            a.x = read(),a.y = read(),a.x1 = read(),a.y1 = read();a.id = tot; 
            if(a.x == a.x1 && a.y == a.y1) ans[tot] = 0; 
            else ans[tot] = 0x3f3f3f3f; 
        } 
        solve(1,1,n,m,1,tot); 
        for(int i = 1;i <= tot;++ i) printf("%d
    ",ans[i]); 
        return 0; 
    } 
     
    
    
  • 相关阅读:
    年近30,朋友聚会都聊什么?
    2016世界最热门的编程语言与薪资揭秘
    程序员的春天来了,最美赏花旅游地十大攻略
    雄联盟工程师独家分享:如何使开发更有效率
    小偷被抓叫嚣:我不偷警察没饭吃
    3.7女生节:被程序员男友送的奇葩礼物宠哭了
    最适合程序员加班吃的6大营养美食
    谷歌汽车出误判曝光 6大奇葩科技更牛
    【程序员的爱情】彼岸花开谁又种下了执念
    分享10个免费或便宜的Photoshop替代工具
  • 原文地址:https://www.cnblogs.com/sssy/p/9439414.html
Copyright © 2020-2023  润新知