【ZJOI2016】旅行者

分治+Dij

 

也没想象中的难写,就是有轻微卡常

 

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#include<ext/pb_ds/priority_queue.hpp>
const int maxn = 20100;
using std::max;
using std::min;
int n,m;
int dis[maxn],vis[maxn];
struct P{
    int x,y,dis;
    __attribute__((always_inline)) operator int()const{return (x-1)*m+y;}
    __attribute__((always_inline)) int operator <(const P&b)const{return dis>b.dis;}
};
struct Q{P a,b;int ans;}b[100100];
inline void down(int&x,int y){if(x>y)x=y;}
struct T{
    P to;
    int nxt,v;
}way[maxn<<2];
int h[maxn],num;
inline void adde(P x,P y,int v){
    way[++num]={y,h[x],v},h[x]=num;
    way[++num]={x,h[y],v},h[y]=num;
}
__gnu_pbds::priority_queue<P>q;
__gnu_pbds::priority_queue<P>::point_iterator iter[maxn];
inline void run(int x,int y,int x1,int y1,int x2,int y2){
    for(int i=x1;i<=x2;++i)
        for(int j=y1;j<=y2;++j)
            dis[(i-1)*m+j]=1e9,iter[(i-1)*m+j]=q.push({i,j,(int)1e9});
    dis[(x-1)*m+y]=0,q.modify(iter[(x-1)*m+y],{x,y,0});
    while(!q.empty()){
        P t=q.top();q.pop();int Ds = dis[t];
        for(int i=h[t];i;i=way[i].nxt){
            P z = way[i].to;int Z=z;
            if(x1 <= z.x && z.x <= x2 && y1 <= z.y && z.y <= y2 && dis[Z]>Ds+way[i].v){
                z.dis=dis[Z]=Ds+way[i].v;
                q.modify(iter[Z],z);
            }
        }
    } 
}
inline void solve(int x1,int y1,int x2,int y2,std::vector<Q*>&v){
    if(x1 > x2 || y1 > y2 || v.empty())return ;
    if(x1 == x2 && y1 == y2){
        for(Q*&i:v)i->ans=0;
        return ;
    }
    if(x2-x1 >= y2-y1){
        int mid = x1 + x2 >> 1;
        for(int i=y1;i<=y2;++i){
            run(mid,i,x1,y1,x2,y2);
            for(Q*&i:v)down(i->ans,dis[i->a]+dis[i->b]);
        }
        std::vector<Q*> v1,v2;
        for(Q*i:v){
            if(max(i->a.x,i->b.x) < mid)v1.emplace_back(i);
            if(min(i->a.x,i->b.x) > mid)v2.emplace_back(i);
        }
        solve(x1,y1,mid-1,y2,v1),solve(mid+1,y1,x2,y2,v2);
    }else{
        int mid=y1 + y2 >> 1;
        for(int i=x1;i<=x2;++i){
            run(i,mid,x1,y1,x2,y2);
            for(Q*i:v)down(i->ans,dis[i->a]+dis[i->b]);
        }
        std::vector<Q*> v1,v2;
        for(Q*&i:v){
            if(max(i->a.y,i->b.y) < mid)v1.emplace_back(i);
            if(min(i->a.y,i->b.y) > mid)v2.emplace_back(i);
        }
        solve(x1,y1,x2,mid-1,v1),solve(x1,mid+1,x2,y2,v2);
    }
}
char buf[(int)3e7],*vin=buf-1;
char bufo[(int)3e7],*vout=bufo-1;
inline void pc(int x){*++vout=x;}
inline void put(int x){if(x>9)put(x/10);pc(x%10+48);}
#define getchar() (*++vin)
int x,ch;
inline int read(){
    while(isspace(ch=getchar()));x=ch&15;
    while(isdigit(ch=getchar()))x=x*10+(ch&15);
    return x;
}
int main(){
    fread(buf,1,sizeof buf,stdin);
    n=read(),m=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<m;++j){
            adde({i,j},{i,j+1},read());
        }
    for(int i=1;i<n;++i)
        for(int j=1;j<=m;++j){
            adde({i,j},{i+1,j},read());
        }
    int q=read();;
    std::vector<Q*> v;
    for(int i=1;i<=q;++i)
        b[i].a.x=read(),b[i].a.y=read(),b[i].b.x=read(),b[i].b.y=read(),b[i].ans=2e9,v.push_back(b+i);
    solve(1,1,n,m,v);
    for(int i=1;i<=q;++i)
        put(b[i].ans),pc(10);
    fwrite(bufo,1,vout-bufo+1,stdout);
}

 

转载于:https://www.cnblogs.com/skip1978/p/10340982.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值