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\)分治. 首先把询问离线, ...
随机推荐
- 在vs2005中添加lib库的方法
方法一:在用到lib的地方加上 //强烈推荐这种方法.#pragma comment(lib,"libname.lib") 方法二: 点击菜单命令 “项目/属性”, ...
- eclipse 添加库
Window ->Preferences ->Java ->Build Path ->User Libraries New,起个名字,如myLibrary add jars,添 ...
- 简说 call() 、apply() 、bind()
对于这三个方法,我想一部分人还是比较陌生的. 所以今天来个简单的介绍~ 我们可以将call()和apply()看作是某个对象的方法,通过调用方法的形式来间接调用函数.call()和apply()的第一 ...
- BZOJ2163: 复杂的大门
BZOJ2163: 复杂的大门 Description 你去找某bm玩,到了门口才发现要打开他家的大门不是一件容易的事……他家的大门外有n个站台,用1到n的正整数编号.你需要对每个站台访问一定次数以后 ...
- Mysql的Merge存储引擎实现分表查询
对于数据量很大的一张表,i/o效率底下,分表势在必行! 使用程序分,对不同的查询,分配到不同的子表中,是个解决方案,但要改代码,对查询不透明. 好在mysql 有两个解决方案: Partition(分 ...
- spring cloud-服务注册
正常的服务模块,注册到注册中心,让别的服务发现,调用服务 创建“服务提供方” 下面我们创建提供服务的客户端,并向服务注册中心注册自己. 假设我们有一个提供计算功能的微服务模块,我们实现一个RESTfu ...
- atomic_cmpxchg()/Atomic_read()/Atomic_set()/Atomic_add()/Atomic_sub()/atomi
[ 1.atomic_read与atomic_set函数是原子变量的操作,就是原子读和原子设置的作用.2.原子操作,就是执行操作的时候,其数值不会被其它线程或者中断所影响3.原子操作是linux内核中 ...
- HDU1964 Pipes —— 插头DP
题目链接:https://vjudge.net/problem/HDU-1964 Pipes Time Limit: 5000/1000 MS (Java/Others) Memory Limi ...
- HashSe、LinkedHashSet、TreeSet(java基础知识十七)
1.HashSet存储字符串并遍历 * 特点:无序.无索引.无重复 HashSet存储字符串并遍历 HashSet<String> hs = new HashSet<>(); ...
- 开发工具、Object类(java基础知识十一)
1.常见开发工具介绍 * A:操作系统自带的记事本软件 * B:高级记事本软件 * C:集成开发环境 IDE * (Integrated Development Environment) * ...