当时已经没心情做题(qi liao)了,写了个分块搞(pian)了50分。
实际上分块和分治的思想是差不多的,就直接讲分治吧。。
首先转离线操作,然后对于某一个矩形区间x∈[lx,rx],y∈[ly,ry],然后要求出所有源点和汇点都在其中的询问,且路径不超出所在区间的答案。不妨设rx-lx>ly-ty,那么对x坐标进行分治,即将这个区间分成两块,那么对于某一个询问,有两种情况:
1.如果询问的起点和终点在两个不同的块,那么一定会经过中轴线上的一点;
2.如果在同一块,那么有可能经过中轴线;也有可能路径只在那一块中,就可以递归分治了;
那么对于某一块,求出中轴线到所在块的所有点的距离,更新一下答案;然后递归分治。
考虑用dijkstra+heap跑最短路,那么就大概是O(N^1.5logN)的(因为思想和kd-tree是差不多的吧所以时间也一样)。本地测试后两个点dijkstra+heap的时间接近spfa的一半,但是为什么uoj上jiry_2的spfa(可能是?)跑的飞快?
AC代码如下:
#include<iostream> #include<cstdio> #define inf 1000000000 #define getp(x,y) (x-1)*n+y #define N 100005 using namespace std; int n,m,cnt,tot,fst[N],pnt[N],len[N],nxt[N],q[N],id[N],d[N],ans[N]; struct node{ int x1,y1,x2,y2,id; }a[N],b[N]; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } void add(int x,int y,int z){ pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot; } void goup(int x){ int y=q[x],t=d[y]; for (; x>1 && t<d[q[x>>1]]; x>>=1){ q[x]=q[x>>1]; id[q[x]]=x; } q[x]=y; id[y]=x; } void godown(int x){ int y=x<<1,z=q[x],t=d[z]; if (y<cnt && d[q[y|1]]<d[q[y]]) y|=1; while (y<=cnt && d[q[y]]<t){ q[x]=q[y]; id[q[x]]=x; x=y; y<<=1; if (y<cnt && d[q[y|1]]<d[q[y]]) y|=1; } q[x]=z; id[z]=x; } void dijk(int sta,int x1,int x2,int y1,int y2){ int i,j,x,y,p,u,v; cnt=1; q[1]=sta; id[sta]=1; d[sta]=0; for (i=x1; i<=x2; i++) for (j=y1; j<=y2; j++){ x=getp(i,j); if (x!=sta){ d[x]=inf; q[++cnt]=x; id[x]=cnt; } } while (cnt){ x=q[1]; q[1]=q[cnt--]; id[q[1]]=1; godown(1); for (p=fst[x]; p; p=nxt[p]){ y=pnt[p]; u=(y-1)/n+1; v=(y-1)%n+1; if (u>=x1 && u<=x2 && v>=y1 && v<=y2 && d[x]+len[p]<d[y]){ d[y]=d[x]+len[p]; goup(id[y]); } } } } void solve(int x1,int x2,int y1,int y2,int l,int r){ if (l>r) return; int i,j,k,mid; if (x2-x1>y2-y1){ mid=(x1+x2)>>1; for (i=y1; i<=y2; i++){ dijk(getp(mid,i),x1,x2,y1,y2); for (j=l; j<=r; j++) ans[a[j].id]=min(ans[a[j].id],d[getp(a[j].x1,a[j].y1)]+d[getp(a[j].x2,a[j].y2)]); } j=l-1; k=r+1; for (i=l; i<=r; i++) if (a[i].x1<mid && a[i].x2<mid) b[++j]=a[i]; else if (a[i].x1>mid && a[i].x2>mid) b[--k]=a[i]; for (i=l; i<=j; i++) a[i]=b[i]; solve(x1,mid-1,y1,y2,l,j); for (i=k; i<=r; i++) a[i]=b[i]; solve(mid+1,x2,y1,y2,k,r); } else{ mid=(y1+y2)>>1; for (i=x1; i<=x2; i++){ dijk(getp(i,mid),x1,x2,y1,y2); for (j=l; j<=r; j++) ans[a[j].id]=min(ans[a[j].id],d[getp(a[j].x1,a[j].y1)]+d[getp(a[j].x2,a[j].y2)]); } j=l-1; k=r+1; for (i=l; i<=r; i++) if (a[i].y1<mid && a[i].y2<mid) b[++j]=a[i]; else if (a[i].y1>mid && a[i].y2>mid) b[--k]=a[i]; for (i=l; i<=j; i++) a[i]=b[i]; solve(x1,x2,y1,mid-1,l,j); for (i=k; i<=r; i++) a[i]=b[i]; solve(x1,x2,mid+1,y2,k,r); } } int main(){ m=read(); n=read(); int i,j,x; for (i=1; i<=m; i++) for (j=1; j<n; j++){ x=read(); add(getp(i,j),getp(i,j+1),x); add(getp(i,j+1),getp(i,j),x); } for (i=1; i<m; i++) for (j=1; j<=n; j++){ x=read(); add(getp(i,j),getp(i+1,j),x); add(getp(i+1,j),getp(i,j),x); } int cas=read(); for (i=1; i<=cas; i++){ a[i].x1=read(); a[i].y1=read(); a[i].x2=read(); a[i].y2=read(); a[i].id=i; ans[i]=inf; } solve(1,m,1,n,1,cas); for (i=1; i<=cas; i++) printf("%d\n",ans[i]); return 0; }
by lych
2016.3.25