bzoj4456: [Zjoi2016]旅行者

Posted Achen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4456: [Zjoi2016]旅行者相关的知识,希望对你有一定的参考价值。

传送门

题解传送门

zjoi难得碰到一道会做的题,,然而听说卡spfa又卡常?

bz上还算是蹭着时限过了。。

大常数选手大概说的就是我吧。。

技术分享图片
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=2e5+7;
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
typedef long long LL;
using namespace std;
int n,m,q,ans[N];

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!=-&&(ch<0||ch>9)) ch=getchar();
    if(ch==-) f=-1,ch=getchar();
    for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f;
}

int ecnt,fir[N],nxt[N<<1],to[N<<1],val[N];
void add(int u,int v,int w) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}

int get(int x,int y) { return (x-1)*m+y; }
void get(int xx,int &x,int &y) { y=xx%m; if(!y) y=m; x=xx/m; if(xx%m) x++; }
int in(int x,int y,int l,int r,int L,int R) { return x>=l&&x<=r&&y>=L&&y<=R;  }

struct node {
    int x,y,xx,yy,id;
}qs[N],lq[N],rq[N];

int dis[N],vis[N];
struct dj {
    int x,dis;
    dj(int x,int dis):x(x),dis(dis){}
    friend bool operator <(const dj&A,const dj&B) {
        return A.dis>B.dis;
    }
};
priority_queue<dj>que;

void dijkstra(int s,int l,int r,int L,int R) {
    For(i,l,r) For(j,L,R) {
        int x=get(i,j);
        dis[x]=ans[0]; vis[x]=0;
    }
    dis[s]=0;
    while(!que.empty()) que.pop();
    que.push(dj(s,0));
    while(!que.empty()) {
        dj x=que.top();
        que.pop();
        if(vis[x.x]||x.dis!=dis[x.x]) continue;
        vis[x.x]=1;
        for(int i=fir[x.x];i;i=nxt[i]) if(!vis[to[i]]) {
            int xx,yy; get(to[i],xx,yy);
            if(in(xx,yy,l,r,L,R)) {
                if(dis[to[i]]>dis[x.x]+val[i]) {
                    dis[to[i]]=dis[x.x]+val[i];
                    que.push(dj(to[i],dis[to[i]])); 
                }
            }
        }
    } 
}

void solve(int l,int r,int L,int R,int ql,int qr) {
    if(l>r||L>R||ql>qr) return;
    if(r-l<=R-L) {
        int mid=((L+R)>>1),ll=0,rr=0;
        For(i,l,r) {
            dijkstra(get(i,mid),l,r,L,R);
            For(j,ql,qr) {
                ans[qs[j].id]=min(ans[qs[j].id],dis[get(qs[j].x,qs[j].y)]+dis[get(qs[j].xx,qs[j].yy)]);
                if(i==l) {
                    if(in(qs[j].x,qs[j].y,l,r,L,mid)&&in(qs[j].xx,qs[j].yy,l,r,L,mid)) lq[++ll]=qs[j];
                    else if(in(qs[j].x,qs[j].y,l,r,mid+1,R)&&in(qs[j].xx,qs[j].yy,l,r,mid+1,R)) rq[++rr]=qs[j];
                }
            }
        }
        For(i,1,ll) qs[ql+i-1]=lq[i]; For(i,1,rr) qs[ql+ll+i-1]=rq[i];
        if(l==r||L==R) return;
        solve(l,r,L,mid,ql,ql+ll-1); solve(l,r,mid+1,R,ql+ll,ql+ll+rr-1);
    }
    else {
        int mid=((l+r)>>1),ll=0,rr=0;
        For(i,L,R) {
            dijkstra(get(mid,i),l,r,L,R);
            For(j,ql,qr) {
                ans[qs[j].id]=min(ans[qs[j].id],dis[get(qs[j].x,qs[j].y)]+dis[get(qs[j].xx,qs[j].yy)]);
                if(i==L) {
                    if(in(qs[j].x,qs[j].y,l,mid,L,R)&&in(qs[j].xx,qs[j].yy,l,mid,L,R)) lq[++ll]=qs[j];
                    else if(in(qs[j].x,qs[j].y,mid+1,r,L,R)&&in(qs[j].xx,qs[j].yy,mid+1,r,L,R)) rq[++rr]=qs[j];
                }
            }
        }
        For(i,1,ll) qs[ql+i-1]=lq[i]; For(i,1,rr) qs[ql+ll+i-1]=rq[i];
        if(l==r||L==R) return;
        solve(l,mid,L,R,ql,ql+ll-1); solve(mid+1,r,L,R,ql+ll,ql+ll+rr-1);
    }
}

//#define DEBUG 
int main() {
#ifdef DEBUG
    freopen("4456.in","r",stdin);
    freopen("4456.out","w",stdout);
#endif
    read(n); read(m);
    For(i,1,n) 
        For(j,1,m-1) {
            int w; read(w);
            add(get(i,j),get(i,j+1),w);
        }    
    For(i,1,n-1)
        For(j,1,m) {
            int w; read(w);
            add(get(i,j),get(i+1,j),w);
        }
    read(q);
    For(i,1,q) {
        read(qs[i].x); read(qs[i].y);
        read(qs[i].xx); read(qs[i].yy);
        qs[i].id=i;
    }
    memset(ans,127/3,sizeof(ans));
    solve(1,n,1,m,1,q);
    For(i,1,q) printf("%d\n",ans[i]);
    return 0;
}
/*
2 2
2
3
6 4
2
1 1 2 2
1 2 2 1
*/
View Code

 

以上是关于bzoj4456: [Zjoi2016]旅行者的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4456 [Zjoi2016]旅行者 / UOJ #184 ZJOI2016旅行者

bzoj4456 [Zjoi2016]旅行者

●BOZJ 4456 [Zjoi2016]旅行者

4456: [Zjoi2016]旅行者|分治+最短路

ZJOI2016旅行者

ZJOI2016