[ZJOI 2016]旅行者 Solution

題意:給一個矩陣,QQ個詢問,每次詢問兩點最短路。
考慮最暴力的做法,每次直接暴力跑最短路,然後計算答案。這樣的不足之處顯然在於最短路上面,那麼如何優化這個過程?
考慮計算所有的答案。
也就是分治,每次選擇一條邊,將它切開,考慮它對哪些詢問有影響。

  • 如果一個詢問的兩個點必須經過這條線,那麼最優答案肯定在這條線上,對這條線的每個點做一遍最短路。然後去更新這些詢問的答案。
  • 如果一個點的兩端點不需要經過這條線,最優答案也是有可能在這條線上的,還是對它們更新答案,然後繼續分治下去。

考慮到時間問題,每次應該切開最長邊,這樣可以做最少次數的最短路。
code:code:

#include <bits/stdc++.h>
#define regi register int
int n,m;
int totq;
int head[1000001],tot;
int dist[1000001];
std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > >que;
struct edge{
	int to;
	int nxt;
	int w;
}e[1000001];
struct Question{
	int lx;
	int ly;
	int rx;
	int ry;
	int id;
}q[1000001],tmp[1000001];
int ans[1000001];
inline int read(){
	int r=0,w=0,c;
	for(;!isdigit(c=getchar());r=c);
	for(w=c^48;isdigit(c=getchar());w=w*10+(c^48));
	return r^45?w:-w;
}
int get_number(int x,int y){
	return (x-1)*m+y;
}
std::pair<int,int> return_number(int x){
	return (x%m)?std::make_pair(x/m+1,x%m):std::make_pair(x/m,m);
}
int ok(int x,int y,int lx,int ly,int rx,int ry){
	return lx<=x&&x<=rx&&ly<=y&&y<=ry;
}
void add(int x,int y,int z){
	e[++tot]={y,head[x],z};
	head[x]=tot;
	e[++tot]={x,head[y],z};
	head[y]=tot;
}
void dijkstra(int lx,int ly,int rx,int ry,int x){
	for(regi i=lx;i<=rx;++i)
	  for(regi j=ly;j<=ry;++j){
	    dist[get_number(i,j)]=0x3f3f3f3f;
	  }
	dist[x]=0;
	que.push({dist[x],x});
	while(!que.empty()){
		int X=que.top().second,Y=que.top().first;
		que.pop();
		for(regi i=head[X];i;i=e[i].nxt){
			regi y=e[i].to;
			std::pair<int,int>pp=return_number(y);
			if(pp.first<lx||pp.first>rx||pp.second<ly||pp.second>ry)
			  continue;
			if(dist[y]>dist[X]+e[i].w){
				dist[y]=dist[X]+e[i].w;
				que.push({dist[y],y});
			}
		}
	}
}
void solve(int lx,int rx,int ly,int ry,int l,int r){
	if(lx==rx&&ly==ry)
	  return;
	if(rx-lx>=ry-ly){
		int mid=lx+rx>>1;
		for(regi i=ly;i<=ry;++i){
		  dijkstra(lx,ly,rx,ry,get_number(mid,i));
		  for(regi j=l;j<=r;++j)
		    ans[q[j].id]=std::min(ans[q[j].id],dist[get_number(q[j].lx,q[j].ly)]+dist[get_number(q[j].rx,q[j].ry)]);
		}
		int nl=l-1,nr=r+1;
		for(regi j=l;j<=r;++j)
		  if(ok(q[j].lx,q[j].ly,lx,ly,mid,ry)&&ok(q[j].rx,q[j].ry,lx,ly,mid,ry))
		    tmp[++nl]=q[j];
		  else
		    if(ok(q[j].lx,q[j].ly,mid+1,ly,rx,ry)&&ok(q[j].rx,q[j].ry,mid+1,ly,rx,ry))
		      tmp[--nr]=q[j];
		for(regi j=l;j<=nl;++j)
		  q[j]=tmp[j];
		for(regi j=r;j>=nr;--j)
		  q[j]=tmp[j];
		solve(lx,mid,ly,ry,l,nl);
	  solve(mid+1,rx,ly,ry,nr,r);
	}
	else{
		int mid=ly+ry>>1;
		for(regi i=lx;i<=rx;++i){
			dijkstra(lx,ly,rx,ry,get_number(i,mid));
			for(regi j=l;j<=r;++j)
			  ans[q[j].id]=std::min(ans[q[j].id],dist[get_number(q[j].lx,q[j].ly)]+dist[get_number(q[j].rx,q[j].ry)]);
		}
		int nl=l-1,nr=r+1;
		for(regi j=l;j<=r;++j)
		  if(ok(q[j].lx,q[j].ly,lx,ly,rx,mid)&&ok(q[j].rx,q[j].ry,lx,ly,rx,mid))
		    tmp[++nl]=q[j];
		  else
		    if(ok(q[j].lx,q[j].ly,lx,mid+1,rx,ry)&&ok(q[j].rx,q[j].ry,lx,mid+1,rx,ry))
		      tmp[--nr]=q[j];
		for(regi j=l;j<=nl;++j)
		  q[j]=tmp[j];
		for(regi j=r;j>=nr;--j)
		  q[j]=tmp[j];
		solve(lx,rx,ly,mid,l,nl);
		solve(lx,rx,mid+1,ry,nr,r);
	}
}
main(){
  n=read();
  m=read();
  for(regi i=1;i<=n;++i)
    for(regi j=1;j<m;++j){
    	regi x=read();
    	add(get_number(i,j),get_number(i,j+1),x);
    }
  for(regi i=1;i<n;++i)
    for(regi j=1;j<=m;++j){
    	regi x=read();
      add(get_number(i,j),get_number(i+1,j),x);
    }
  totq=read();
  for(regi i=1;i<=totq;++i){
  	q[i].lx=read();
  	q[i].ly=read();
  	q[i].rx=read();
  	q[i].ry=read();
  	q[i].id=i;
  }
  for(regi i=1;i<=totq;++i)
    ans[i]=(q[i].lx==q[i].rx&&q[i].ly==q[i].ry)?0:0x3f3f3f3f;
  solve(1,n,1,m,1,totq);
  for(regi i=1;i<=totq;++i)
    printf("%d\n",ans[i]);
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章