zoukankan      html  css  js  c++  java
  • BZOJ 4456: [Zjoi2016]旅行者

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

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

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

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

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

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

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

    因此总复杂度(T(S)=2T(frac{S}{2})+O(Ssqrt Slog S)),套用主定理,复杂度为(O(Ssqrt Slog 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('
    ');
    		}
    		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;	
    }
    
  • 相关阅读:
    录制caf 转 mp3
    关于百度地图iOS中 paopaoView 警告的处理方法
    iphone JB开发小记(四)theos、iosOpenDev的调试
    USB 漏洞影响超100万来自不同供应商的路由器
    进程 线程 纤程 中断
    synchronized、ReentrantLock、volatile
    TimeUnit用法
    2021年vivo互联网技术最受欢迎文章TOP25
    前端质量提升利器马可代码覆盖率平台
    zyh@163.net
  • 原文地址:https://www.cnblogs.com/cjjsb/p/12274889.html
Copyright © 2011-2022 走看看