bzoj 4456 [Zjoi2016]旅行者
题面
https://www.lydsy.com/JudgeOnline/problem.php?id=4456
题解
分治
设当前work的区间为(x1,y1,x2,y2)
我们将长边分成两半
不妨设长边是(x1,x2)
那么令mid=(x1+x2)/2
对于分界线(mid,y1)~(mid,y2)的所有点 我们做最短路
得到分界线上所有点到区间里任意点的最短路
那么对于询问(sx,sy,tx,ty) 我们可以枚举分界线上某一点(mid,y) 并且用dist((mid,y),(sx,sy))+dist((mid,y),(tx,ty))更新答案
然后对于(sx,sy)和(tx,ty)都落在分界线同一侧的询问我们递归求解
这样做的正确性:每一组询问,一定会经过某次的分界线,在计算到这条分界线的时候就可以算到答案
复杂度:T(n)=4T(n/2)+O(n*(m+nlogm)) m为边数也就是n^2
那么T(n)=n^3(这是n约等于m的情况) 可以通过这道题
n和m差距大的时候更快
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll; ll read(){
ll x=,f=;char c=getchar();
while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
while(c>='' && c<=''){x=x*+c-'';c=getchar();}
return x*f;
} const int maxn=;
int n,m,q;
int a[][maxn],b[][maxn];
bool vis[][maxn];
bool flag;
int res[]; struct P{
int x;
pair<int,int> y;
bool operator <(const P &a) const{
return x>a.x;
}
}; priority_queue<P> pq; struct query{
int a,b,c,d;
int p,ans;
void input(){
a=read(),b=read(),c=read(),d=read();
}
} que[]; int dis[][maxn];
int num[][maxn]; void update(int nwx,int nwy,int nwdis){
//cout<<nwx<<' '<<nwy<<' '<<nwdis<<endl;
if(dis[nwx][nwy]>nwdis){
dis[nwx][nwy]=nwdis;
pq.push(P{nwdis,make_pair(nwx,nwy)});
}
}
void doit(int x,int y,int X1,int Y1,int X2,int Y2){
//cout<<X1<<' '<<Y1<<' '<<X2<<' '<<Y2<<' '<<x<<' '<<y<<endl;
for(int i=X1;i<=X2;i++)
for(int j=Y1;j<=Y2;j++)
dis[i][j]=1e9,vis[i][j]=;
dis[x][y]=;
pq.push(P{,make_pair(x,y)});
while(!pq.empty()){
P nw=pq.top();
pq.pop();
int X=nw.y.first,Y=nw.y.second;
//cout<<X<<' '<<Y<<' '<<dis[X][Y]<<endl;
if(vis[X][Y]) continue;
vis[X][Y]=;int dist=dis[X][Y];
if(X>X1) update(X-,Y,dist+b[X-][Y]);
if(X<X2) update(X+,Y,dist+b[X][Y]);
if(Y>Y1) update(X,Y-,dist+a[X][Y-]);
if(Y<Y2) update(X,Y+,dist+a[X][Y]);
}
} void solve(int nwa,int nwb,int nwc,int nwd,int l,int r){
//cout<<nwa<<' '<<nwb<<' '<<nwc<<' '<<nwd<<endl;
if(l>r) return;
int len1=nwc-nwa+,len2=nwd-nwb+;
if(len1>=len2){
int md=(nwa+nwc)>>;
for(int j=nwb;j<=nwd;j++){
doit(md,j,nwa,nwb,nwc,nwd);
for(int k=l;k<=r;k++){
//cout<<que[k].p<<' '<<dis[que[k].a][que[k].b]<<' '<<dis[que[k].c][que[k].d]<<endl;
que[k].ans=min(que[k].ans,dis[que[k].a][que[k].b]+dis[que[k].c][que[k].d]);
}
}
if(nwa<md){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].a<md && que[i].c<md) pos++,swap(que[i],que[pos]);
}
solve(nwa,nwb,md-,nwd,l,pos);
}
if(md<nwc){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].a>md && que[i].c>md) pos++,swap(que[i],que[pos]);
}
solve(md+,nwb,nwc,nwd,l,pos);
}
}
else{
int md=(nwb+nwd)>>;
for(int i=nwa;i<=nwc;i++){
doit(i,md,nwa,nwb,nwc,nwd);
for(int k=l;k<=r;k++){
//cout<<que[k].p<<' '<<dis[que[k].a][que[k].b]<<' '<<dis[que[k].c][que[k].d]<<endl;
que[k].ans=min(que[k].ans,dis[que[k].a][que[k].b]+dis[que[k].c][que[k].d]);
}
}
if(nwb<md){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].b<md && que[i].d<md) pos++,swap(que[i],que[pos]);
}
solve(nwa,nwb,nwc,md-,l,pos);
}
if(md<nwd){
int pos=l-;
for(int i=l;i<=r;i++){
if(que[i].b>md && que[i].d>md) pos++,swap(que[i],que[pos]);
}
solve(nwa,md+,nwc,nwd,l,pos);
}
}
} int main(){
#ifdef LZT
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
n=read();m=read();
if(n>m) flag=;
for(int i=;i<=n;i++){
for(int j=;j<m;j++){
if(!flag) a[i][j]=read();
else b[j][i]=read();
}
}
for(int i=;i<n;i++){
for(int j=;j<=m;j++){
if(!flag) b[i][j]=read();
else a[j][i]=read();
}
}
q=read();
for(int i=;i<=q;i++){
que[i].input();
if(flag) swap(que[i].a,que[i].b),swap(que[i].c,que[i].d);
que[i].p=i;que[i].ans=2e9;
}
if(flag) swap(n,m); solve(,,n,m,,q); for(int i=;i<=q;i++)
res[que[i].p]=que[i].ans;
for(int i=;i<=q;i++)
printf("%d\n",res[i]);
return ;
} /*
2 2
2
3
6 4
2
1 1 2 2
1 2 2 1
*/
Review
分治还是比较明显的
然而数据的处理十分麻烦
因为条件是n×m的范围
所以我们得同时考虑n=m和n>>m的情况
代码中的处理方法是跟别人学的 很棒棒 要多写几遍
bzoj 4456 [Zjoi2016]旅行者的更多相关文章
- BZOJ.4456.[ZJOI2016]旅行者(分治 Dijkstra)
题目链接 \(Description\) 给定\(n\times m\)的带边权网格图.\(Q\)次询问从点\((x_i,y_i)\)到点\((x_j,y_j)\)的最短路. \(n\times m\ ...
- 4456: [Zjoi2016]旅行者
4456: [Zjoi2016]旅行者 https://www.lydsy.com/JudgeOnline/problem.php?id=4456 分析: 每次对当前矩阵按长边化一条分治线,然后在对分 ...
- ●BOZJ 4456 [Zjoi2016]旅行者
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4456 题解: 分治好题.大致做法如下:对于一开始的矩形区域,过较长边的中点把矩形区域分为两个 ...
- [BZOJ4456] [Zjoi2016]旅行者 分治+最短路
4456: [Zjoi2016]旅行者 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 777 Solved: 439[Submit][Status] ...
- P3350 [ZJOI2016]旅行者
题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...
- bzoj4456: [Zjoi2016]旅行者
题目链接 bzoj4456: [Zjoi2016]旅行者 题解 网格图,对于图分治,每次从中间切垂直于长的那一边, 对于切边上的点做最短路,合并在图两边的答案. 有点卡常 代码 #include< ...
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
[BZOJ4456][Zjoi2016]旅行者 Description 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形 ...
- Luogu 3350 [ZJOI2016]旅行者
BZOJ 4456 听若干个大佬讲过$n$遍终于写掉了. 我把时限基本上跑满了2333…… 分治 + 最短路. 首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然 ...
- luogu3350 [ZJOI2016]旅行者
链接 P3350 [ZJOI2016]旅行者 题目大意:给出网格图,求两点之间最短路,多组询问. \(n*m\leq10^5\ \ q\leq 10^5\) 考虑\(CDQ\)分治. 首先把询问离线, ...
随机推荐
- JAVA BigDecimal 高精度运算
文章参考一位博友,由于时间太久忘了链接,见谅! public class BigDecimalUtils { private static final int DIV_SCALE = 10;// 除法 ...
- 使网页适应UIWebView的宽度
比較简单的做法是:在- (void)webViewDidFinishLoad:这种方法中,改动JavaScript的值: //UIWebViewDelegate - (void)webViewDidF ...
- Handler之IdleHandler
MessageQueue提供了另一类消息,IdleHandler 如果返回false,每次轮询都会调用(理论上应该可以做一些别的东西) Looper.myQueue().addIdleHandler( ...
- mysql数据库隔离级别及其原理、Spring的7种事物传播行为
一.事务的基本要素(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...
- (linux)container_of()宏
在学习Linux驱动的过程中,遇到一个宏叫做container_of. 该宏定义在include/linux/kernel.h中,首先来贴出它的代码: /** * container_of - ...
- POJ1077 Eight —— 经典的搜索问题
题目链接:http://poj.org/problem?id=1077 Eight Time Limit: 1000MS Memory Limit: 65536K Total Submission ...
- 一步一步学Silverlight 2系列(26):基本图形
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...
- SPFA 最短路 带负权边的---- 粗了解
SPFA(Shortest Path Faster Algorithm)是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算. 算法大致流程是用一个队列来进行维护. 初始时将源加入队列 ...
- I.MX6 2014 u-boot 测试修改
/************************************************************************* * I.MX6 2014 u-boot 测试修改 ...
- Synchronized之三:Synchronized与线程中断、线程wait
线程中断 见<Thread之八:interrupt中断> 正如中断二字所表达的意义,在线程运行(run方法)中间打断它,在Java中,提供了以下3个有关线程中断的方法 //中断线程(实例方 ...