给你一张地图,给你q次询问,每次问你从A点到B点,最大能移动多大的箱子。

把每个点所能容纳的最大箱子求出来(BFS,八连通,一开始将所有边界点和障碍点入队)。然后从大到小排序。然后用并查集将相邻(四联通)的点依次链接起来,如果不路径压缩的话,那么两个节点的LCA的所能容纳的箱子大小就是答案。于是用并查集辅助建树,之后离线询问,然后Tarjan跑个LCA即可。

O(n^2+qlog(n)),log是因为map记录答案。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
using namespace std;
vector<int>ask[1010*1010];
int dx[]={0,1,0,-1,1,1,-1,-1},dy[]={1,0,-1,0,1,-1,1,-1};
int e,v[1010*1010],first[1010*1010],next[1010*1010];
void AddEdge(int U,int V){v[++e]=V;next[e]=first[U];first[U]=e;
}
struct Point{int x,y;Point(const int &x,const int &y){this->x=x;this->y=y;}Point(){}
};
bool operator < (const Point &a,const Point &b){return a.x!=b.x ? a.x<b.x : a.y<b.y;
}
map<Point,int>anss;
struct Node{Point p;int d;Node(const Point &p,const int &d){this->p=p;this->d=d;}
};
int n,siz[1010][1010],Siz[1010*1010],m,K;
int id[1010][1010];
bool cmp(const Point &a,const Point &b){return siz[a.x][a.y]>siz[b.x][b.y];
}
char a[1010][1010];
queue<Node>q;
bool vis[1010][1010];
Point ps[1010*1010];
int fa[1010*1010];
int find(int x){return x==fa[x] ? x : fa[x]=find(fa[x]);
}
Point qa[300010],qb[300010];
bool not_rt[1010*1010];
int ans[1010*1010];
bool VIS[1010*1010];
void LCA(int u)
{ans[u]=u;for(int i=first[u];i;i=next[i]){LCA(v[i]);int f1=find(u),f2=find(v[i]);fa[f1]=f2;ans[find(u)]=u;}VIS[u]=true;for(int i=0;i<ask[u].size();i++)if(VIS[ask[u][i]]){
//      printf("%d %d %d %d\n",min(u,ask[u][i]),max(u,ask[u][i]),ans[find(ask[u][i])],Siz[ans[find(ask[u][i])]]);anss[Point(min(u,ask[u][i]),max(u,ask[u][i]))]=Siz[ans[find(ask[u][i])]];}
}
bool sb_q[300010];
int main(){
//  freopen("h.in","r",stdin);scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%s",a[i]+1);}for(int i=0;i<=n+1;++i){q.push(Node(Point(i,0),0));vis[i][0]=1;q.push(Node(Point(i,n+1),0));vis[i][n+1]=1;}for(int i=0;i<=n+1;++i){q.push(Node(Point(0,i),0));vis[0][i]=1;q.push(Node(Point(n+1,i),0));vis[n+1][i]=1;}for(int i=1;i<=n;++i){for(int j=1;j<=n;++j){if(a[i][j]=='#'){q.push(Node(Point(i,j),0));vis[i][j]=1;}}}for(int i=1;i<=n;++i){for(int j=1;j<=n;++j){id[i][j]=++m;}}m=0;while(!q.empty()){Node U=q.front(); q.pop();int x=U.p.x,y=U.p.y;for(int i=0;i<8;++i){int tx=x+dx[i],ty=y+dy[i];if(tx>=1 && tx<=n && ty>=1 && ty<=n && !vis[tx][ty]){q.push(Node(Point(tx,ty),U.d+1));siz[tx][ty]=Siz[id[tx][ty]]=2*U.d+1;vis[tx][ty]=1;}}}
//  for(int i=1;i<=n;++i){
//      for(int j=1;j<=n;++j){
//          printf("%d ",siz[i][j]);
//      }
//      puts("");
//  }for(int i=1;i<=n;++i){for(int j=1;j<=n;++j){if(siz[i][j]){ps[++m]=Point(i,j);}}}for(int i=1;i<=m;++i){fa[id[ps[i].x][ps[i].y]]=id[ps[i].x][ps[i].y];}sort(ps+1,ps+m+1,cmp);memset(vis,0,sizeof(vis));for(int i=1;i<=m;++i){int x=ps[i].x,y=ps[i].y;for(int j=0;j<4;++j){int tx=x+dx[j],ty=y+dy[j];if(a[tx][ty]=='.' && vis[tx][ty]){int rt=find(id[tx][ty]);if(rt!=find(id[x][y])){AddEdge(id[x][y],rt);
//                  printf("%d %d\n",id[x][y],rt);not_rt[rt]=1;fa[rt]=id[x][y];}}}vis[x][y]=1;}scanf("%d",&K);for(int i=1;i<=K;++i){scanf("%d%d%d%d",&qa[i].x,&qa[i].y,&qb[i].x,&qb[i].y);int f1=find(id[qa[i].x][qa[i].y]),f2=find(id[qb[i].x][qb[i].y]);if(f1==f2){ask[id[qa[i].x][qa[i].y]].push_back(id[qb[i].x][qb[i].y]);ask[id[qb[i].x][qb[i].y]].push_back(id[qa[i].x][qa[i].y]);}else{sb_q[i]=1;}}for(int i=1;i<=m;++i){fa[id[ps[i].x][ps[i].y]]=id[ps[i].x][ps[i].y];}for(int i=1;i<=m;++i){if(!not_rt[id[ps[i].x][ps[i].y]]){LCA(id[ps[i].x][ps[i].y]);}}for(int i=1;i<=K;++i){if(sb_q[i]){puts("0");}else{printf("%d\n",anss[Point(min(id[qa[i].x][qa[i].y],id[qb[i].x][qb[i].y]),max(id[qa[i].x][qa[i].y],id[qb[i].x][qb[i].y]))]);}}return 0;
}

转载于:https://www.cnblogs.com/autsky-jadek/p/7214356.html

【BFS】【并查集】【Tarjan】【LCA】Gym - 101173H - Hangar Hurdles相关推荐

  1. Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)

    题目链接:点击查看 题目大意:给出一个 n∗nn*nn∗n 的矩阵,有些位置存在障碍物,现在有 qqq 次询问,每次询问给出两个点 st=(x1,y1),ed=(x2,y2)st=(x1,y1),ed ...

  2. POJ2186——并查集+Tarjan算法求强连通分量

    算法讨论:这题陷阱比较多.首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中.这个我们用并查集来实现就可以了.强连通分量的求法就很简单了,正 ...

  3. hdu1181变形课dfs/bfs/并查集三种解法(java)

    题目链接 Problem Description 呃-变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个 ...

  4. hdu dfs入门java_hdu1181变形课dfs/bfs/并查集三种解法(java)

    题目链接 Problem Description 呃-变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个 ...

  5. 牛客小白月赛25 C白魔法师 (bfs | 并查集)

    题目描述:题目链接 题意分析: n个节点 n-1条边,非常明显的树形结构(题目中就有说 ),因此不需要考虑环的情况. 树上有两种颜色,一种是白色一种是黑色,我们可以推断出这题应该是考虑连通块的大小,那 ...

  6. upc 潜入苏拉玛 多源bfs + 并查集 + 思维

    潜入苏拉玛 时间限制: 1 Sec 内存限制: 128 MB 题目描述 你接到了⼀个任务,让你潜⼊苏拉玛城,和线⼈取得联络.苏拉玛的地图是⼀张N个点M条边的⽆向图,每个点表⽰苏拉玛城的⼀个路⼜,每条边 ...

  7. [Leedcode][JAVA][第200题][岛屿数量][DFS][BFS][并查集]

    [问题描述] 第200题 岛屿数量 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量.岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成 ...

  8. BZOJ 4668: 冷战 并查集暴力LCA(雾)

    利用并查集按秩合并,保存每个点合并的时间: 求时间时,就一直跳u=fa[u],并记录路径上时间的最大值,代表最后一次合并的时间 #include<cstdio> #include<i ...

  9. 【割边缩点】解题报告:POJ - 3694 - Network(Tarjan割边缩点 + LCA + 并查集优化)

    POJ - 3694 - Network 给定一张N个点M条边的无向连通图,然后执行Q次操作,每次向图中添加一条边,并且询问当前无向图中"桥"的数量.N≤105,M≤2∗105,Q ...

最新文章

  1. 马斯克新视频:Boring公司将优先解决公交快速通勤
  2. iis6中FTP配置的技巧和细节
  3. 9.9学python靠谱吗-走进小学教材,Python何德何能?9图对比道出真相
  4. iOS开发中视图相关的小笔记:push、modal、popover、replace、custom
  5. efcore调用函数_如何在EF Core 使用存储过程
  6. 机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(五)
  7. SystemCenter2012SP1实践(23)私有云的权限设计
  8. 外国小哥,把整个 CNN 都给可视化了,卷积、池化清清楚楚!
  9. Java程序中fix time_Java Position.setFixTime方法代码示例
  10. Flutter实战一Flutter聊天应用(十八)
  11. 失败后的从容离开,无意之中也许会再次点亮希望之光
  12. 2006 年100 款最佳安全工具谱
  13. 11. 文件上传漏洞
  14. 可视化管理_供应链可视化管理作用与现状分析
  15. ShaderForge插件介绍详解
  16. 机械制图之工程图线型
  17. git回退版本 简单易懂
  18. AutoSF- Searching Scoring Functions for Knowledge Graph Embedding
  19. 从底层源码认知Arraylist
  20. 视觉中国图片编码_学习编码第14天的应用视觉设计第4部分

热门文章

  1. 简单网页制作html语言,html基本操作,看了这些你就能做简易网页
  2. dedecms怎么改php版本_Linux下如何安装DedeCMS?
  3. vmware虚拟机迁移到hyperv_ProxmoxVE 之 V2V迁移(vmware-PVE)
  4. java 继承 模型_java – 画布形状模型的继承与组合?
  5. 计算机视觉算法——目标检测网络总结
  6. 【每周CV论文推荐】换脸算法都有哪些经典的思路?
  7. 2021Lazada开店入驻最新流程Lazada新店运营思路分享
  8. 全球及中国手持式吸尘器行业供应需求及未来投资潜力预测报告2022-2027年
  9. 妙用0元素数组 实现大小可变结构体
  10. 2019最新Python学习路线图:如何用Python创建微信机器人