【ZJOI2016】旅行者

题面

https://www.luogu.org/problem/P3350

网格图上最短路

题解

离线+分治。

最短路两种情况,穿过中间边和没穿过中间边。

对于当前区域包含的询问:

先找当前区域中间边(尽可能切成正方形)

对中间边上的点,求当前区域内所有的点对其的最短路。

如果两点被中间边切断,那这次一定能得到最优解,可以去掉。

如果两点没被中间边切断,递归下去。

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#define ri register int
#define S 50050
#define INF 1e9
#define Q 100050

using namespace std;

int dis[S];
bool vis[S];
int n,m,q;
int x1[Q],y1[Q],x2[Q],y2[Q];
int ans[Q];
int cur[Q];
int curt[Q];
vector<int> to[S],len[S];

void add_edge(int x,int y,int z) {
  to[x].push_back(y); len[x].push_back(z);
  to[y].push_back(x); len[y].push_back(z);
}

struct node {
  int x,d;
  bool operator < (const node &rhs) const {
    return d>rhs.d;
  }
};

inline int id(int x,int y){return (x-1)*m+y;}

inline bool chujie(int num,int lx,int rx,int ly,int ry) {
  if ((num-1)/m+1<lx || (num-1)/m+1>rx) return 1;
  if ((num-1)%m+1<ly || (num-1)%m+1>ry) return 1;
  return 0;
}

void clear(int lx,int rx,int ly,int ry) {
  for (ri i=lx;i<=rx;i++)
    for (ri j=ly;j<=ry;j++) {
      dis[id(i,j)]=INF,vis[id(i,j)]=0;
    }
}

void dij(int lx,int rx,int ly,int ry,int s){
  priority_queue<node> q;
  dis[s]=0;
  q.push((node){s,0});
  while (!q.empty()) {
    int x=q.top().x; q.pop();
    if (vis[x]) continue;
    vis[x]=1;
    for (ri i=0;i<to[x].size();i++) {
      if (chujie(to[x][i],lx,rx,ly,ry)) continue;
      if (dis[to[x][i]]>dis[x]+len[x][i]) {
        dis[to[x][i]]=dis[x]+len[x][i];
        q.push((node){to[x][i],dis[to[x][i]]});
      }
    }
  }
}

void solve(int lx,int rx,int ly,int ry,int vl,int vr) {
  if (lx>rx || ly>ry || vl>vr) return;
  if (rx-lx<ry-ly) {
    int mid=(ly+ry)/2;
    for (ri i=lx;i<=rx;i++) {
      clear(lx,rx,ly,ry);
      dij(lx,rx,ly,ry,id(i,mid));
      for (ri j=vl;j<=vr;j++) {
        int p=cur[j];
        if (dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])]<ans[p]) ans[p]=dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])];
      }
    }
    int nl=vl-1,nr=vr+1;
    for (ri i=vl;i<=vr;i++) {
      int p=cur[i];
      if (y1[p]<mid && y2[p]<mid) curt[++nl]=p;
      if (y1[p]>mid && y2[p]>mid) curt[--nr]=p;
    }
    for (ri i=vl;i<=vr;i++) cur[i]=curt[i];
    solve(lx,rx,ly,mid-1,vl,nl);
    solve(lx,rx,mid+1,ry,nr,vr);
  }
  else {
    int mid=(lx+rx)/2;
    for (ri i=ly;i<=ry;i++) {
      clear(lx,rx,ly,ry);
      dij(lx,rx,ly,ry,id(mid,i));
      for (ri j=vl;j<=vr;j++) {
        int p=cur[j];
        if (dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])]<ans[p]) ans[p]=dis[id(x1[p],y1[p])]+dis[id(x2[p],y2[p])];
      }
    }
    int nl=vl-1,nr=vr+1;
    for (ri i=vl;i<=vr;i++) {
      int p=cur[i];
      if (x1[p]<mid && x2[p]<mid) curt[++nl]=p;
      if (x1[p]>mid && x2[p]>mid) curt[--nr]=p;
    }
    for (ri i=vl;i<=vr;i++) cur[i]=curt[i];
    solve(lx,mid-1,ly,ry,vl,nl);
    solve(mid+1,rx,ly,ry,nr,vr);
  }
}

int main(){
  int c;
  scanf("%d %d",&n,&m);
  for (ri i=1;i<=n;i++) {
    for (ri j=1;j<m;j++) {
      scanf("%d",&c);
      int x=id(i,j),y=id(i,j+1);
      add_edge(x,y,c);
    }
  }
  for (ri i=1;i<n;i++) {
    for (ri j=1;j<=m;j++) {
      scanf("%d",&c);
      int x=id(i,j),y=id(i+1,j);
      add_edge(x,y,c);
    }
  }
  scanf("%d",&q);
  for (ri i=1;i<=q;i++) {
    scanf("%d %d %d %d",&x1[i],&y1[i],&x2[i],&y2[i]);
    ans[i]=INF;
    cur[i]=i;
  }
  solve(1,n,1,m,1,q);
  for (ri i=1;i<=q;i++) printf("%d\n",ans[i]);
  return 0;
}

原文地址:https://www.cnblogs.com/shxnb666/p/11278050.html

时间: 2024-08-02 05:15:35

【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)最少需要花多少

【BZOJ4456】 [Zjoi2016]旅行者 / 【UOJ #184】 【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)最少需要

ZJOI2018酱油记

ZJOI2018酱油记 前言 作为\(HN\)高一蒟蒻选手,毕竟去了趟\(ZJOI\)玩泥巴 不写点游记还是不太好吧. 今天来补一补. Day0 星期天,中午,我们一群人滚到了学校门口 然后集合,滚去坐地铁连校车都不提供,差评 高铁站感觉很久很久很久没有来过了 换句话说,我很久很久很久没有离开过长沙了 忽然出去一趟,似乎也挺爽的. 在车上,拿出电脑打了几句红警,一个人玩好无聊 然后在车厢里漫无目的的游走,顺便%%%雅礼的巨佬们 下午到了衢州, 跟长沙一比较, 长沙果然是省会城市啊,光是看一眼就能

黯淡蓝点:旅行者号64亿公里外回望地球...

1990年“旅行者”号探测器在即将飞出太阳系的时候,最后一次回眸我们的家园--地球! “旅行者”号探测器从40亿英里(约64亿公里)之外拍摄了上面两张地球照片.第一张照片中,地球仅是一个0.12个像素大小的圆点.著名天文学家卡尔·萨根将其描绘成“硕大的宇宙夜幕中一个孤独的圆点,对我来说,它强调了我们在更友善.更积极地处理相互之间的关系上的责任,以及保护和爱惜这个黯淡蓝点的责任,这是人类已知的唯一家园.” 地球是在这个浩翰宇宙剧院里的一个细小舞台. 想想从那些将令们和皇帝们溢出的血河,他们的光荣与

【NOIP考前模拟赛】纯数学方法推导——旅行者问题

一.写在前面 这题似乎是一道原创题目(不是博主原创),所以并不能在任何OJ上评测,博主在网盘上上传了数据(网盘地址:http://pan.baidu.com/s/1mibdMXi),诸位看官需者自取.另外博主使用此题并没有获得出题人授权,如果出题人看到这篇blog并认为在下侵犯了您的权利,请用站内消息与在下联系,在下会立即删除这篇blog,给您带来的困扰之处敬请谅解. 博主上传这道题主要是因为这题牵扯许多数学运算,推导过程比较复杂,但是却没有用到任何算法或者数学定理,可以说这是一道想法题的典范.

NOIP模拟赛-旅行者问题 解题报告

题目 :http://www.tsinsen.com/P9143 题是我发现.想测可以测.已经分享出去了. 旅行者问题 [问题描述] lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行.lahub想去参观n个目的地(都在一条直道上).lahub在起点开始他的旅行.第i个目的地和起点的距离为ai千米(ai为非负整数).不存在两个目的地和起点的距离相同. 从第i个目的地走到第j个目的地所走的路程为 |ai-aj|千米.我们把参观n个目的地的顺序称作一次“旅行”.lahub

ZJOI2016

首先做了T2的旅行者,看到bz上面过的人数比较多.. 考试的时候完全没有想太多.一闪而过了分块思想,然后就没有然后了.. 大视野上面有题解,竟然是一个初中生写的..? 正解其实是“分治”,每次选择中轴线,不会势能分析,感觉考场上想出来也肯定不敢打.. #include<cstdio> #include<algorithm> #define inf 1000000000 #define N 100010 using namespace std; int dis[N],ans[N],q

4455[Zjoi2016]小星星 容斥+dp

4455: [Zjoi2016]小星星 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 527  Solved: 317[Submit][Status][Discuss] Description 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细 线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了n?1条细线,但 通过这些细线,这颗小星星还是被串在一起,也就是这

uoj #185. 【ZJOI2016】小星星

#185. [ZJOI2016]小星星 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有 nn 颗小星星,用 mm 条彩色的细线串了起来,每条细线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了 n−1n−1 条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树. 小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星.如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上