BZOJ 4456: [Zjoi2016]旅行者

有点诡异的说,但是这个被叫做套路题?我哭了

直接讲正解,考虑分治处理矩形,每次在矩形的两边之间取一条较长的,然后取这条边的中点连线,把原矩形分成两个子矩形

考虑此时的询问必然只有两种类型:两点在两个/同一个子矩形内,其中在同一个子矩形内的答案可以递归处理

那么此时我们考虑更新前一种情况的答案,由于此题中连边的特性我们发现此时这条边一定会跨过两个矩形的分界线

那么我们取出分界线上的所有点,从每个点开始跑一遍DJ求出到矩形内其它点的距离,让更新答案即可

乍一看很暴力,我们来算一算复杂度,令\(S=nm\),考虑每次分治枚举的分界线上的点数目,我们发现这个剖分方法和KD-Tree是相同的

那么它的复杂度和KD-Tree一样(只不过是满的),为\(O(S\sqrt S)\),那么我们每次分治的复杂度就是\(O(S\sqrt S\log S)\)(注意DJ里面的复杂度不用乘\(\sqrt S\),因为这是多次累加出来的)

因此总复杂度\(T(S)=2T(\frac{S}{2})+O(S\sqrt S\log S)\),套用主定理,复杂度为\(O(S\sqrt S\log S)\)

#include<cstdio>
#include<cctype>
#include<queue>
#include<iostream>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=100005,INF=1e9;
struct point
{
	int x,y;
};
struct ques
{
	point u,v; int id;
}q[N],tp1[N],tp2[N]; int n,m,tot,mpl[N],*id[N],x,ans[N],dis[N];
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[15];
	public:
		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		Tp inline void write(T x)
		{
			RI ptop=0; while (pt[++ptop]=x%10,x/=10);
			while (ptop) pc(pt[ptop--]+48); pc('\n');
		}
		inline void flush(void)
		{
			fwrite(Fout,1,Ftop-Fout,stdout);
		}
		#undef tc
		#undef pc
}F;
inline bool in(const point& p,CI lx,CI rx,CI ly,CI ry)
{
	return lx<=p.x&&p.x<=rx&&ly<=p.y&&p.y<=ry;
}
namespace DJ
{
	struct edge
	{
		point pos; int to,nxt,v;
	}e[N<<2]; int head[N],cnt; bool vis[N];
	struct data
	{
		int val,id;
		friend inline bool operator < (const data& A,const data& B)
		{
			return A.val>B.val;
		}
	}; priority_queue <data> hp;
	inline void addedge(CI x1,CI y1,CI x2,CI y2,CI z)
	{
		int x=id[x1][y1],y=id[x2][y2];
		e[++cnt]=(edge){(point){x2,y2},y,head[x],z}; head[x]=cnt;
		e[++cnt]=(edge){(point){x1,y1},x,head[y],z}; head[y]=cnt;
	}
	#define to e[i].to
	inline void Dijkstra(CI st,CI lx,CI rx,CI ly,CI ry)
	{
		RI i,j; for (i=lx;i<=rx;++i) for (j=ly;j<=ry;++j)
		dis[id[i][j]]=INF,vis[id[i][j]]=0; hp.push((data){dis[st]=0,st});
		while (!hp.empty())
		{
			int now=hp.top().id; hp.pop(); if (vis[now]) continue; vis[now]=1;
			for (i=head[now];i;i=e[i].nxt)
			if (in(e[i].pos,lx,rx,ly,ry)&&dis[to]>dis[now]+e[i].v)
			hp.push((data){dis[to]=dis[now]+e[i].v,to});
		}
	}
	#undef to
};
inline void solve(CI lx=1,CI rx=n,CI ly=1,CI ry=m,CI l=1,CI r=tot)
{
	if (l>r) return; if (lx==rx&&ly==ry) { for (RI i=l;i<=r;++i) ans[q[i].id]=0; return; }
	RI i,j,ct1=0,ct2=0; if (rx-lx>=ry-ly)
	{
		int mid=lx+rx>>1; for (i=ly;i<=ry;++i)
		for (DJ::Dijkstra(id[mid][i],lx,rx,ly,ry),j=l;j<=r;++j)
		ans[q[j].id]=min(ans[q[j].id],dis[id[q[j].u.x][q[j].u.y]]+dis[id[q[j].v.x][q[j].v.y]]);
		for (i=l;i<=r;++i)
		{
			if (in(q[i].u,lx,mid,ly,ry)&&in(q[i].v,lx,mid,ly,ry)) tp1[++ct1]=q[i];
			if (in(q[i].u,mid+1,rx,ly,ry)&&in(q[i].v,mid+1,rx,ly,ry)) tp2[++ct2]=q[i];
		}
		for (i=1;i<=ct1;++i) q[l+i-1]=tp1[i]; for (i=1;i<=ct2;++i) q[l+ct1+i-1]=tp2[i];
		solve(lx,mid,ly,ry,l,l+ct1-1); solve(mid+1,rx,ly,ry,l+ct1,l+ct1+ct2-1);
	} else
	{
		int mid=ly+ry>>1; for (i=lx;i<=rx;++i)
		for (DJ::Dijkstra(id[i][mid],lx,rx,ly,ry),j=l;j<=r;++j)
		ans[q[j].id]=min(ans[q[j].id],dis[id[q[j].u.x][q[j].u.y]]+dis[id[q[j].v.x][q[j].v.y]]);
		for (i=l;i<=r;++i)
		{
			if (in(q[i].u,lx,rx,ly,mid)&&in(q[i].v,lx,rx,ly,mid)) tp1[++ct1]=q[i];
			if (in(q[i].u,lx,rx,mid+1,ry)&&in(q[i].v,lx,rx,mid+1,ry)) tp2[++ct2]=q[i];
		}
		for (i=1;i<=ct1;++i) q[l+i-1]=tp1[i]; for (i=1;i<=ct2;++i) q[l+ct1+i-1]=tp2[i];
		solve(lx,rx,ly,mid,l,l+ct1-1); solve(lx,rx,mid+1,ry,l+ct1,l+ct1+ct2-1);
	}
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j; for (F.read(n),F.read(m),id[0]=mpl,i=1;i<=n;++i)
	for (id[i]=id[i-1]+m+1,j=1;j<=m;++j) id[i][j]=(i-1)*m+j;
	for (i=1;i<=n;++i) for (j=1;j<m;++j) F.read(x),DJ::addedge(i,j,i,j+1,x);
	for (i=1;i<n;++i) for (j=1;j<=m;++j) F.read(x),DJ::addedge(i,j,i+1,j,x);
	for (F.read(tot),i=1;i<=tot;++i) ans[i]=INF,
	F.read(q[i].u.x),F.read(q[i].u.y),F.read(q[i].v.x),F.read(q[i].v.y),q[i].id=i;
	for (solve(),i=1;i<=tot;++i) F.write(ans[i]); return F.flush(),0;	
}
posted @ 2020-02-07 22:17  空気力学の詩  阅读(234)  评论(0编辑  收藏  举报