zoukankan      html  css  js  c++  java
  • 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路

    【BZOJ4456】[Zjoi2016]旅行者

    Description

    小Y来到了一个新的城市旅行。她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m)。她发现不同的道路路况不同,所以通过不同的路口需要不同的时间。通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1,j)需要时间c(i,j)。注意这里的道路是双向的。小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要花多少时间。

    Input

    第一行包含 2 个正整数n,m,表示城市的大小。
    接下来n行,每行包含m?1个整数,第i行第j个正整数表示从一个路口到另一个路口的时间r(i,j)。
    接下来n?1行,每行包含m个整数,第i行第j个正整数表示从一个路口到另一个路口的时间c(i,j)。
    接下来一行,包含1个正整数q,表示小Y的询问个数。
    接下来q行,每行包含4个正整数 x1,y1,x2,y2,表示两个路口的位置。

    Output

    输出共q行,每行包含一个整数表示从一个路口到另一个路口最少需要花的时间。

    Sample Input

    2 2
    2
    3
    6 4
    2
    1 1 2 2
    1 2 2 1

    Sample Output

    6
    7

    题解:能把各种各样奇怪的做法和最短路结合起来我也是服了~

    思考怎么分治,如果矩形的x2-x1>y2-y1,那么我们就按x分治,因为此时一列的点数是小于sqrt(n)的,所以我们可以枚举分割线上的所有点,以这些点为源点都跑一次最短路,然后考虑每个询问:

    如果询问的两个点在分治的不同侧,则最短路可能经过分割线上的每个点,用分割线上每个点到这两个点的距离和更新答案,然后这个询问我们就不用管了。
    如果询问的两个点在分治的同侧,则最短路也可能经过分割线上的点,依旧要更新答案,然后将这个询问放到对应的分治结构去。

    所以最终的复杂度是$O(n sqrt{n} log(n))$的。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    #define P(A,B) ((A-1)*m+B)
    using namespace std;
    const int maxn=20010;
    int n,m,Q;
    int dis[maxn],v[maxn][4],vis[maxn],ans[100010];
    int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
    struct query
    {
    	int x1,y1,x2,y2,org;
    }q[100010],q1[100010],q2[100010];
    struct node
    {
    	int val,x,y;
    	node() {}
    	node(int a,int b,int c) {val=a,x=b,y=c;}
    	bool operator < (const node &a) const
    	{
    		return val>a.val;
    	}
    };
    priority_queue<node> pq;
    void dijkstra(int sx,int sy,int lx,int rx,int ly,int ry)
    {
    	int i,j,x,y,tx,ty;
    	for(i=lx;i<=rx;i++)	for(j=ly;j<=ry;j++)	dis[P(i,j)]=1<<30,vis[P(i,j)]=0;
    	dis[P(sx,sy)]=0,pq.push(node(0,sx,sy));
    	while(!pq.empty())
    	{
    		x=pq.top().x,y=pq.top().y,pq.pop();
    		if(vis[P(x,y)])	continue;
    		vis[P(x,y)]=1;
    		for(i=0;i<4;i++)
    		{
    			tx=x+dx[i],ty=y+dy[i];
    			if(tx>=lx&&tx<=rx&&ty>=ly&&ty<=ry&&dis[P(tx,ty)]>dis[P(x,y)]+v[P(x,y)][i])
    			{
    				dis[P(tx,ty)]=dis[P(x,y)]+v[P(x,y)][i];
    				pq.push(node(dis[P(tx,ty)],tx,ty));
    			}
    		}
    	}
    }
    void solve(int lx,int rx,int ly,int ry,int lq,int rq)
    {
    	if(lq>rq)	return ;
    	if(lx==rx&&ly==ry)
    	{
    		for(int i=lq;i<=rq;i++)	ans[q[i].org]=0;
    		return ;
    	}
    	if(rx-lx>ry-ly)
    	{
    		int i,j,mid=(lx+rx)>>1,h1=0,h2=0;
    		for(i=ly;i<=ry;i++)
    		{
    			dijkstra(mid,i,lx,rx,ly,ry);
    			for(j=lq;j<=rq;j++)	ans[q[j].org]=min(ans[q[j].org],dis[P(q[j].x1,q[j].y1)]+dis[P(q[j].x2,q[j].y2)]);
    		}
    		for(i=lq;i<=rq;i++)
    		{
    			if(q[i].x1<=mid&&q[i].x2<=mid)	q1[++h1]=q[i];
    			if(q[i].x1>mid&&q[i].x2>mid)	q2[++h2]=q[i];
    		}
    		for(i=lq;i<=lq+h1-1;i++)	q[i]=q1[i-lq+1];
    		for(i=lq+h1;i<=lq+h1+h2-1;i++)	q[i]=q2[i-lq-h1+1];
    		solve(lx,mid,ly,ry,lq,lq+h1-1),solve(mid+1,rx,ly,ry,lq+h1,lq+h1+h2-1);
    	}
    	else
    	{
    		int i,j,mid=(ly+ry)>>1,h1=0,h2=0;
    		for(i=lx;i<=rx;i++)
    		{
    			dijkstra(i,mid,lx,rx,ly,ry);
    			for(j=lq;j<=rq;j++)	ans[q[j].org]=min(ans[q[j].org],dis[P(q[j].x1,q[j].y1)]+dis[P(q[j].x2,q[j].y2)]);
    		}
    		for(i=lq;i<=rq;i++)
    		{
    			if(q[i].y1<=mid&&q[i].y2<=mid)	q1[++h1]=q[i];
    			if(q[i].y1>mid&&q[i].y2>mid)	q2[++h2]=q[i];
    		}
    		for(i=lq;i<=lq+h1-1;i++)	q[i]=q1[i-lq+1];
    		for(i=lq+h1;i<=lq+h1+h2-1;i++)	q[i]=q2[i-lq-h1+1];
    		solve(lx,rx,ly,mid,lq,lq+h1-1),solve(lx,rx,mid+1,ry,lq+h1,lq+h1+h2-1);
    	}
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,j;
    	for(i=1;i<=n;i++)	for(j=1;j<m;j++)	v[P(i,j)][1]=v[P(i,j+1)][3]=rd();
    	for(i=1;i<n;i++)	for(j=1;j<=m;j++)	v[P(i,j)][0]=v[P(i+1,j)][2]=rd();
    	Q=rd();
    	for(i=1;i<=Q;i++)	q[i].x1=rd(),q[i].y1=rd(),q[i].x2=rd(),q[i].y2=rd(),q[i].org=i;
    	memset(ans,0x3f,sizeof(ans));
    	solve(1,n,1,m,1,Q);
    	for(i=1;i<=Q;i++)	printf("%d
    ",ans[i]);
    	return 0;
    }
  • 相关阅读:
    A+B for Input-Output Practice (VIII)
    A+B for Input-Output Practice (VI)
    A+B for Input-Output Practice (VII)
    A+B for Input-Output Practice (IV)
    1.1.4 A+B for Input-Output Practice (V)
    1.1.3 A+B for Input-Output Practice (III)
    基础练习 龟兔赛跑预测
    基础练习 回形取数
    Python实用黑科技——以某个字段进行分组
    Python黑科技神奇去除马赛克
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7691157.html
Copyright © 2011-2022 走看看