题解 P8876 【[传智杯 #5 初赛] H-二人的世界】
题解
搜索题。
注意一个重要性质:水流之间可视为互不干扰的。虽然确实有强度更大的水流可以覆盖强度更小的水流这样的设定,但容易发现强度更大的水流,可以流到的空间,包含了强度更小的水流。
(感性理解一下)
于是可以考虑,从高到低计算每个高度有哪些位置是有水流的。下面定义结构体
- 先开一个
\text{map}\lang \text{Pos3},\text{bool}\rang 存一下整个空间里有哪些位置是有实体方块的,记作B 。 - 再开一个
\text{map}\lang \text{Pos2},\text{bool}\rang 存一下当前高度有哪些方块是有水方块的,记作W 。
对于输入进来的每个实体方块
首先将所有实体方块按照
为什么不枚举
现在我们要对
但是可以发现,这一层实际有用的目标位置(紧挨在一个实体方块旁边)是不多的,个数是
当
- 先要开一个
\text{map}\lang \text{Pos2},\text{int}\rang 存一下每一个位置到达目标位置的最短距离,记为D 。 - 还要开一个
\text{map}\lang \text{Pos2},\text{int}\rang 存一下P 里面每个位置它的水方块的强度,记为K 。
接着从
当然,如果
最后是时间复杂度分析。上面出现的三个过程时间复杂度全部都是
参考代码
#include<bits/stdc++.h>
#define up(l,r,i) for(int i=l,END##i=r;i<=END##i;++i)
#define dn(r,l,i) for(int i=r,END##i=l;i>=END##i;--i)
using namespace std;
typedef long long i64;
const int INF =2147483647;
struct Pos2{
int x, y;
Pos2(int _x = 0, int _y = 0):x(_x), y(_y){}
const bool operator < (const Pos2 &t) const {
if(x != t.x) return x < t.x;
return y < t.y;
}
const bool operator > (const Pos2 &t) const {
if(x != t.x) return x > t.x;
return y > t.y;
}
const bool operator ==(const Pos2 &t) const {
return x == t.x && y == t.y;
}
};
struct Pos3{
int x, y, z;
Pos3(int _x = 0, int _y = 0, int _z = 0):
x(_x), y(_y), z(_z){}
const bool operator < (const Pos3 &t) const {
if(x != t.x) return x < t.x;
if(y != t.y) return y < t.y;
return z < t.z;
}
const bool operator > (const Pos3 &t) const {
if(x != t.x) return x > t.x;
if(y != t.y) return y > t.y;
return z > t.z;
}
const bool operator ==(const Pos3 &t) const {
return x == t.x && y == t.y && z == t.z;
}
};
const int BASE = 13331;
struct Hash{
unsigned operator ()(const Pos2 t) const{
return t.x * BASE + t.y;
}
unsigned operator ()(const Pos3 t) const{
return (t.x * BASE + t.y) * BASE + t.z;
}
};
unordered_map<Pos3, bool, Hash> B; // 存 (x, y, z) 是否有方块
unordered_map<Pos2, bool, Hash> V; // 存 (x, y, h + 1) 有没有使用过
unordered_map<Pos2, int , Hash> D; // 存 (x, y) 的最短路程
unordered_map<Pos2, bool, Hash> W; // 存 (x, y, h + 1) 位置有没有水方块
unordered_map<Pos2, int , Hash> K; // 存 (x, y, h + 1) 位置水方块的强度
const int DIR[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
const int MAXN = 2e5 + 3;
int n, p, X[MAXN], Y[MAXN], Z[MAXN], I[MAXN];
int qread(){
int w = 1, c, ret;
while((c = getchar()) > '9' || c < '0') w = (c == '-' ? -1 : 1); ret = c - '0';
while((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + c - '0';
return ret * w;
}
bool cmp(int a, int b){ return Z[a] > Z[b]; }
int _x0, _y0;
int main(){
n = qread(), p = qread(), _x0 = qread(), _y0 = qread();
W[Pos2(_x0, _y0)] = true;
up(1, n, i){
X[i] = qread(), Y[i] = qread(), Z[i] = qread(), I[i] = i;
B[Pos3(X[i], Y[i], Z[i])] = true;
}
sort(I + 1, I + 1 + n, cmp);
up(1, n, i){
int h = Z[I[i]], j;
queue <Pos2> P, Q;
for(j = i;j <= n && Z[I[j]] == h;++ j){
int o = I[j], x = X[o], y = Y[o];
Pos2 u(x, y);
if(W.count(u))
P.push(u), K[u] = p, W.erase(u);
up(0, 3, k){
int nx = x + DIR[k][0];
int ny = y + DIR[k][1];
Pos2 v(nx, ny);
if(!V.count(v) && !B.count(Pos3(nx, ny, h))
&& !B.count(Pos3(nx, ny, h + 1)))
V[v] = true, D[v] = 0, Q.push(v);
}
}
while(!Q.empty()){
Pos2 u = Q.front(); Q.pop(); int x = u.x, y = u.y;
up(0, 3, k){
int nx = x + DIR[k][0];
int ny = y + DIR[k][1];
Pos2 v(nx, ny);
if(!D.count(v) && B.count(Pos3(nx, ny, h))
&& !B.count(Pos3(nx, ny, h + 1)))
D[v] = D[u] + 1, Q.push(v);
}
}
while(!P.empty()){
Pos2 u = P.front(); P.pop(); int x = u.x, y = u.y;
int d = D[u], s = K[u];
if(!B.count(Pos3{x, y, h})){
W[u] = true; continue;
}
if(s == 1) continue;
up(0, 3, k){
int nx = x + DIR[k][0];
int ny = y + DIR[k][1];
Pos2 v(nx, ny);
if( D[v] == d - 1)
if(!K.count(v) && !B.count(Pos3(nx, ny, h + 1)))
K[v] = s - 1, P.push(v);
}
}
i = j - 1, D.clear(), K.clear(), V.clear();
}
printf("%u\n", W.size());
return 0;
}
参考代码
import java.io.*;
import java.util.*;
public class Main {
public static class Vec2d {
public int x, y;
public Vec2d(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
return Arrays.hashCode(new int[] {x, y});
}
public boolean equals(Vec2d vec2d) {
return this.x == vec2d.x && this.y == vec2d.y;
}
@Override
public boolean equals(Object vec2d) {
if (!(vec2d instanceof Vec2d))
return false;
return this.x == ((Vec2d) vec2d).x && this.y == ((Vec2d) vec2d).y;
}
}
public static class Vec3d {
public int x, y, z;
public Vec3d(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public int hashCode() {
return Arrays.hashCode(new int[] {x, y, z});
}
public boolean equals(Vec3d vec2d) {
return this.x == vec2d.x && this.y == vec2d.y && this.z == vec2d.z;
}
@Override
public boolean equals(Object vec2d) {
if (!(vec2d instanceof Vec3d))
return false;
return this.x == ((Vec3d) vec2d).x && this.y == ((Vec3d) vec2d).y && this.z == ((Vec3d) vec2d).z;
}
}
public static class Scanner {
public BufferedReader in;
public StringTokenizer tok;
public String next() {
hasNext();
return tok.nextToken();
}
public String nextLine() {
try {
return in.readLine();
} catch (Exception e) {
return null;
}
}
public long nextLong() {
return Long.parseLong(next());
}
public int nextInt() {
return Integer.parseInt(next());
}
public PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public boolean hasNext() {
while (tok == null || !tok.hasMoreTokens()) try {
tok = new StringTokenizer(in.readLine());
} catch (Exception e) {
return false;
}
return true;
}
public Scanner(InputStream inputStream) {
in = new BufferedReader(new InputStreamReader(inputStream));
}
}
public static Map<Vec3d, Boolean> isblock = new HashMap<>();
public static Map<Vec2d, Boolean> isused = new HashMap<>();
public static Map<Vec2d, Integer> dist = new HashMap<>();
public static Map<Vec2d, Boolean> iswater = new HashMap<>();
public static Map<Vec2d, Integer> strwater = new HashMap<>();
public static final int[] dx = {1, -1, 0, 0}, dy = {0, 0, 1, -1};
public static int n, k, _x0, _y0;
public static int[] x = new int[100050], y = new int[100050], z = new int[100050];
public static List<Integer> var_id = new ArrayList<>();
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
k = scanner.nextInt();
_x0 = scanner.nextInt();
_y0 = scanner.nextInt();
iswater.put(new Vec2d(_x0, _y0), true);
for (int i = 1; i <= n; i++) {
x[i] = scanner.nextInt();
y[i] = scanner.nextInt();
z[i] = scanner.nextInt();
isblock.put(new Vec3d(x[i], y[i], z[i]), true);
var_id.add(i);
}
var_id.sort((x, y) -> z[y] - z[x]);
List<Integer> id = new ArrayList<>();
id.add(0);
for (int i = 0; i < n; ++i)
id.add(var_id.get(i));
for (int i = 0; i < 5; ++i)
id.add(0);
for (int i = 1; i <= n; i++) {
int height = z[id.get(i)];
Queue<Vec2d> p = new LinkedList<>(), q = new LinkedList<>();
// spread at the same height
for (int nid = id.get(i); i <= n && z[nid] == height; ) {
int nx = x[nid], ny = y[nid];
Vec2d u = new Vec2d(nx, ny);
if (iswater.getOrDefault(u, false)) {
iswater.put(u, false);
p.add(u);
strwater.put(u, k);
}
for (int j = 0; j < 4; j++) {
int nx1 = nx + dx[j], ny1 = ny + dy[j];
Vec2d v = new Vec2d(nx1, ny1);
Vec3d v1 = new Vec3d(nx1, ny1, height);
Vec3d v2 = new Vec3d(nx1, ny1, height + 1);
if (!isused.getOrDefault(v, false) && !isblock.getOrDefault(v1, false) && !isblock.getOrDefault(v2, false)) {
isused.put(v, true);
dist.put(v, 0);
q.add(v);
}
}
i++;
nid = id.get(i);
}
i--;
// spread water in Q
while (!q.isEmpty()) {
Vec2d var1 = q.element();
q.remove();
int x = var1.x, y = var1.y;
Vec2d u = new Vec2d(x, y);
for (int j = 0; j < 4; j++) {
int nx = x + dx[j], ny = y + dy[j];
Vec2d v = new Vec2d(nx, ny);
Vec3d v1 = new Vec3d(nx, ny, height);
Vec3d v2 = new Vec3d(nx, ny, height + 1);
if (dist.getOrDefault(v, 0) == 0 && isblock.getOrDefault(v1, false) && !isblock.getOrDefault(v2, false)) {
dist.put(v, dist.get(u) + 1);
q.add(v);
}
}
}
//spread water in P
while (!p.isEmpty()) {
Vec2d var1 = p.element();
p.remove();
int x = var1.x, y = var1.y;
Vec2d u = new Vec2d(x, y);
Vec3d u1 = new Vec3d(x, y, height);
int d = dist.getOrDefault(u, 0), s = strwater.getOrDefault(u, 0);
if (!isblock.getOrDefault(u1, false)) {
iswater.put(u, true);
continue;
}
if (s == 1)
continue;
for (int j = 0; j < 4; j++) {
int nx = x + dx[j], ny = y + dy[j];
Vec2d v = new Vec2d(nx, ny);
Vec3d v1 = new Vec3d(nx, ny, height + 1);
if (dist.getOrDefault(v, 0) == d - 1 && strwater.getOrDefault(v, 0) == 0 && !isblock.getOrDefault(v1, false)) {
strwater.put(v, s - 1);
p.add(v);
}
}
}
isused.clear();
dist.clear();
strwater.clear();
}
int cnt = 0;
for (boolean i : iswater.values()) {
cnt += i ? 1 : 0;
}
System.out.println(cnt);
}
}