首先做了T2的旅行者,看到bz上面过的人数比较多。。
考试的时候完全没有想太多。一闪而过了分块思想,然后就没有然后了。。
大视野上面有题解,竟然是一个初中生写的。。?
正解其实是“分治”,每次选择中轴线,不会势能分析,感觉考场上想出来也肯定不敢打。。
#include<cstdio> #include<algorithm> #define inf 1000000000 #define N 100010 using namespace std; int dis[N],ans[N],q[N],id[N],vet[N],head[N],next[N],pri[N]; int edgenum,cas,cnt,n,m; struct node{int x1,y1,x2,y2,id;}a[N],b[N]; void add(int u,int v,int w) { edgenum++;vet[edgenum]=v;next[edgenum]=head[u]; head[u]=edgenum;pri[edgenum]=w; //printf("%d %d %d\n",u,v,w); } void push_down(int k) { while(k*2<=cnt) { int k1=q[k],k2=q[k*2],k3=q[k*2+1]; if(k*2+1<=cnt&&dis[k1]>dis[k3]&&dis[k3]<dis[k2]) { id[k1]=k*2+1;id[k3]=k;swap(q[k],q[k*2+1]); k=k*2+1; }else if(dis[k1]>dis[k2]) { id[k1]=k*2;id[k2]=k;swap(q[k],q[k*2]);k=k*2; }else break; } } void push_up(int k) { while(k/2>0&&dis[q[k]]<dis[q[k/2]]) { id[q[k]]=k/2;id[q[k/2]]=k;swap(q[k],q[k/2]); k=k/2; } } void dijk(int sta,int x1,int x2,int y1,int y2) { cnt=1;q[1]=sta;id[sta]=1;dis[sta]=0; for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) { int u=(i-1)*m+j; if(u!=sta){dis[u]=inf;q[++cnt]=u;id[u]=cnt;} } while(cnt) { int u=q[1];q[1]=q[cnt--];id[q[1]]=1;push_down(1);int e=head[u];//printf("reng=%d\n",u); while(e>0) { int v=vet[e],xx=(v-(v%m))/m+1,yy=v%m;if(yy==0)yy=m;if(v%m==0)xx--; //printf("ok=%d %d %d\n",v,xx,yy); if(xx>=x1&&xx<=x2&&yy>=y1&&yy<=y2) if(dis[v]>dis[u]+pri[e]) { dis[v]=dis[u]+pri[e]; //printf("ok=%d %d %d\n",u,v,dis[v]); push_up(id[v]); } e=next[e]; } } //printf("sta=%d\n",sta); for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) { int u=(i-1)*m+j; //printf("dis=%d %d\n",u,dis[u]); } } void solve(int x1,int x2,int y1,int y2,int l,int r) { if(l>r)return;int mid; if(x2-x1>y2-y1) { mid=(x1+x2)>>1; for(int i=y1;i<=y2;i++) { int u=(mid-1)*m+i;dijk(u,x1,x2,y1,y2); for(int j=l;j<=r;j++) { int u1=(a[j].x1-1)*m+a[j].y1,u2=(a[j].x2-1)*m+a[j].y2; int t=dis[u1]+dis[u2]; ans[a[j].id]=min(ans[a[j].id],t); } } int j=l-1,k=r+1; for(int 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(int i=l;i<=j;i++)a[i]=b[i];solve(x1,mid-1,y1,y2,l,j); for(int i=k;i<=r;i++)a[i]=b[i];solve(mid+1,x2,y1,y2,k,r); }else { mid=(y1+y2)>>1; for(int i=x1;i<=x2;i++) { int u=(i-1)*m+mid;dijk(u,x1,x2,y1,y2); for(int j=l;j<=r;j++) { int u1=(a[j].x1-1)*m+a[j].y1,u2=(a[j].x2-1)*m+a[j].y2; int t=dis[u1]+dis[u2]; ans[a[j].id]=min(ans[a[j].id],t); } } int j=l-1,k=r+1; for(int 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(int i=l;i<=j;i++)a[i]=b[i];solve(x1,x2,y1,mid-1,l,j); for(int i=k;i<=r;i++)a[i]=b[i];solve(x1,x2,mid+1,y2,k,r); } } int main() { freopen("4456.in","r",stdin); freopen("4456.out","w",stdout); scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<m;j++) { int x,u=(i-1)*m+j,v=(i-1)*m+j+1;scanf("%d",&x); add(u,v,x);add(v,u,x); } for(int i=1;i<n;i++) for(int j=1;j<=m;j++) { int x,u=(i-1)*m+j,v=i*m+j;scanf("%d",&x); add(u,v,x);add(v,u,x); } scanf("%d",&cas); for(int i=1;i<=cas;i++) { scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2); a[i].id=i;ans[i]=inf; } solve(1,n,1,m,1,cas); for(int i=1;i<=cas;i++)printf("%d\n",ans[i]); }
时间: 2024-10-16 12:51:52