当时已经不(fang)想(qi)做(zhi)题(liao)了,写了个分块搞(pian)了50分。
实际上分块和分治的思想是差不多的,就直接讲分治吧。。
首先转离线操作,然后对于某一个矩形区间x∈[lx,rx],y∈[ly,ry],然后要求出所有源点和汇点都在其中的询问,且路径不超出所在区间的答案。不妨设rx-lx>ly-ty,那么对x坐标进行分治,即将这个区间分成两块,那么对于某一个询问,有两种情况:
1.如果询问的起点和终点在两个不同的块,那么一定会经过中轴线上的一点;
2.如果在同一块,那么有可能经过中轴线;也有可能路径只在那一块中,就可以递归分治了;
那么对于某一块,求出中轴线到所在块的所有点的距离,更新一下答案;然后递归分治。
考虑用dijkstra+heap跑最短路,那么就大概是O(N^1.5logN)的(因为思想和kd-tree是差不多的吧所以时间也一样UPD:应该是dijkstra的复杂度)。本地测试后两个点dijkstra+heap的时间接近spfa的一半,但是为什么uoj上jiry_2的spfa(可能是?)跑的飞快?
AC代码如下:
#include
#include
#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>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=x1 && u<=x2 && v>=y1 && v<=y2 && d[x]+len[p]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].x1mid && 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].y1mid && 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
by lych
2016.3.25