我的写法是把每棵主观种的树种下和可能死亡的时间离线排序,然后对于一定存活的树泛洪找到可以依赖它种下的树。
代码中用了一个 D 表示最早种下的时间,在判定一棵树是否死亡时看它旁边的点能否在它死之前种下。
但是如果每次泛洪时去更新 D 显然会 TLE。于是代码中如果 D 不是极大值就退出了。但这样可能会导致判死亡有问题。
所以是数据水了还是我脑子出问题了?
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
#define IOS ios::sync_with_stdio(false), cin.tie(nullptr)
#define MAXN 3000
#define MAXM 100000
const int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int n, m, q, r, k;
struct T {
int t, x, y;//时间,对于 p 数组坐标 (x, y),对于 ob 数组,x = 0/1 表示种下/死亡,y = 编号
bool operator < (const T &o) const{
return t < o.t || (t == o.t && x < o.x) || (t == o.t && x == o.x && y < o.y);
}
} p[MAXM+5], ob[MAXM*2+5];
//p:主动种树
//ob:扫描
bool isby[MAXN+5][MAXN+5];//是否与湖泊相邻/之前种了一棵树还没死
int ans, ispond[MAXN+5][MAXN+5], D[MAXN+5][MAXN+5];
//ispond:是否是湖泊
//D:种下的(最早)时间
inline void Pond() {//预处理与湖泊相邻的点
for (int i = 1, a, b, c, d; i <= q; ++i) {
cin >> a >> b >> c >> d;
ispond[a][b] ^= 1, ispond[a][d + 1] ^= 1, ispond[c + 1][b] ^= 1, ispond[c + 1][d + 1] ^= 1;
}
vector<pair<int, int> > Pos;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
ispond[i][j] ^= ispond[i - 1][j] ^ ispond[i][j - 1] ^ ispond[i - 1][j - 1];
if (ispond[i][j]) Pos.emplace_back(i, j);
}
}
for (auto P : Pos) {
int i = P.first, j = P.second;
isby[i][j] = false;
for (int Dir = 0; Dir < 4; ++Dir) {
int dx = i + dir[Dir][0], dy = j + dir[Dir][1];
if (dx < 1 || dx > n || dy < 1 || dy > m || ispond[dx][dy]) continue;
isby[dx][dy] = true;
}
}
}
void flood_fill(int x, int y, int dist) {//泛洪
if (D[x][y] != D[0][0] /*D[x][y] <= dist*/) return;
//此处存疑,这样不能保证 D 为最小值,可能导致主函数扫描时对死亡的判断条件收缩
D[x][y] = dist;
for (int Dir = 0; Dir < 4; ++Dir) {
int dx = x + dir[Dir][0], dy = y + dir[Dir][1];
if (dx < 1 || dx > n || dy < 1 || dy > m || ispond[dx][dy] || !isby[dx][dy]) continue;
flood_fill(dx, dy, dist + 1);
}
}
int main() {
IOS;
cin >> n >> m >> q >> r >> k;
memset(D, 0x7f, sizeof D);
Pond();
for (int i = 1; i <= r; ++i) {
cin >> p[i].t >> p[i].x >> p[i].y;
ob[i * 2 - 1] = {p[i].t, 0, i};
ob[i * 2] = {p[i].t + k, 1, i};
}
sort(ob + 1, ob + 1 + 2 * r);
for (int i = 1; i <= 2 * r; ++i) {
int cur = ob[i].y;
if (ob[i].t == p[cur].t) {
isby[p[cur].x][p[cur].y] = true;
for (int Dir = 0; Dir < 4; ++Dir) {
int dx = p[cur].x + dir[Dir][0], dy = p[cur].y + dir[Dir][1];
if (isby[dx][dy] || ispond[dx][dy]) {//旁边有湖泊或者旁边挨着湖泊或者有棵主动种的树还没死
flood_fill(p[cur].x, p[cur].y, p[cur].t);
break;
}
}
} else {
bool f = false;
for (int Dir = 0; Dir < 4; ++Dir) {
int dx = p[cur].x + dir[Dir][0], dy = p[cur].y + dir[Dir][1];
if (D[dx][dy] + 1 <= p[cur].t + k) {//这个条件明显不对
f = true;
flood_fill(p[cur].x, p[cur].y, p[cur].t);
break;
}
}
if (!f) isby[p[cur].x][p[cur].y] = false;//死亡
}
}
for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) ans += (D[i][j] != D[0][0]);
cout << ans;
return 0;
}