ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BZOJ-4242 水壶

2020-03-07 15:52:38  阅读:275  来源: 互联网

标签:fa 水壶 maxp 4242 len int edge 建筑物 BZOJ


题目大意

某市是一个被分成$Htimes W$块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有$P$个,编号为$1dots P$。只有建筑物和原野能够进入,而且每次只能走到相邻的区域中,且不能移动到市外。现在需要在各个建筑物之间往返。在原野上每走过一个区域都需要$1$单位的水。原野上不能提供水,但建筑物里有自来水可以将随身携带的水壶装满。

给出该市的地图和$Q$个询问,对于第$i$个询问,输出在建筑物$S_i$和$T_i$之间移动需要水壶的最小容积。

$H,Wleqslant 2000$,$P,Qleqslant 2times 10^5$。


思路

由于可以在建筑物中补充水,从$S_i$走到$T_i$可能会经过多个建筑物,则需要水壶的最小容积为连续经过的两个建筑物之间的距离的最大值。要使路径上的最大距离最小,可以想到最小生成树。

如果以每个建筑物为起点进行BFS,边的数量就达到$O(p^2)$,不可取。可以先把$P$个建筑物全部放入队列中,同时向外扩展,用$id[i]$记下网格中区域$i$最先被哪个建筑物扩展到,$dist[i]$记录扩展的距离。然后讨论相邻的两个区域$i,j$,将最先扩展到这两个区域的建筑物$id[i],id[j]$之间连边,边长为$dist[i]+dist[j]$,这样边的数量就减少到了$O(hw)$,并且一定不会漏掉最小生成树上的边。

然后用Kruskal求出生成树,问题就变成了求树上两点间路径上的最大边权。预处理倍增数组$f[u][i]$,表示$u$号点到$fa[u][i]$的路径上的最大边权:

类似求LCA的过程,将其中某个点倍增向上跳的过程中,用跳过的这一段路径的最大边权更新答案。

另外本题求出的生成树可能是森林,所以每棵树都要DFS一遍求倍增数组,注意判断无解的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=2000+5,maxp=2e5+5;
const int INF=0x3f3f3f3f;

template<typename Tp>
class graph{
public:
  struct edge{
    int to;edge *next;Tp len;
    edge(int to=0,edge *next=0,Tp len=0):to(to),next(next),len(len){}
  };
  int dep[maxp],fa[maxp][25],n,edgtot;
  edge edges[maxp*2],*now[maxp];
  Tp f[maxp][25];
  void insert(int u,int v,Tp w){
    edges[++edgtot]=edge(v,now[u],w),now[u]=edges+edgtot;
  }
  void dfs(int u){
    dep[u]=dep[fa[u][0]]+1;
    int k=ceil(log2(dep[u]));
    for(int i=1;i<=k;i++){
      fa[u][i]=fa[fa[u][i-1]][i-1];
      f[u][i]=max(f[u][i-1],f[fa[u][i-1]][i-1]);
    }
    for(edge *e=now[u];e;e=e->next){
      int v=e->to;
      if(v!=fa[u][0]){fa[v][0]=u,f[v][0]=e->len;dfs(v);}
    }
  }
  Tp lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int s=ceil(log2(n)),k=dep[u]-dep[v];
    Tp ans=0;
    for(int i=0;i<=s;i++)if(k&1<<i)
      ans=max(ans,f[u][i]),u=fa[u][i];
    if(u==v)return ans;
    s=ceil(log2(dep[u]));
    for(int i=s;i>=0;i--)if(fa[u][i]!=fa[v][i]){
      ans=max(ans,max(f[u][i],f[v][i]));
      u=fa[u][i],v=fa[v][i];
    }
    return max(ans,max(f[u][0],f[v][0]));
  }
};
graph<int> g;

struct node{
  int x,y;
  node(int x=0,int y=0):x(x),y(y){}
};
struct edge{
  int a,b,len;
  edge(int a=0,int b=0,int len=0):a(a),b(b),len(len){}
  bool operator<(edge rhs)const{return len>rhs.len;}
};
const int dx[]={-1,1,0,0},dy[]={0,大专栏

标签:fa,水壶,maxp,4242,len,int,edge,建筑物,BZOJ
来源: https://www.cnblogs.com/liuzhongrong/p/12434731.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有