Wannafly挑战赛2 C.Butterfly(线段树优化枚举)
题目链接 C.Butterfly
令$fd[i][j]$为以$s[i][j]$为起点开始往下走最大连续的‘X’个数
令$fl[i][j]$为以$s[i][j]$为起点开始往左下走最大连续的‘X’个数
令$fr[i][j]$为以$s[i][j]$为起点开始往左下走最大连续的‘X’个数
令$a[i][j] = min(fd[i][j], fl[i][j])$, $b[i][j] = min(fd[i][j], fr[i][j])$
对于每一个$(i, j)$, 我们要找到$(i, k)$
使得$k$最大,并且$k >= j$, $k - j + 1 <= min(a[i][j], b[i][k])$
$k - j + 1$必须为奇数
把所有条件整理出来就是
$k - j + 1 <= a[i][j]$
$k - j + 1 <= b[i][k]$
移项得到
$k <= a[i][j] + j - 1$
$k - b[i][k] + 1 <= j$
所以我们可以对$k - b[i][k] + 1$排序,当$j$从$1$扫到$m$的时候每一次确保所有满足$k - b[i][k] + 1$的$k$都已经被添加到线段树中
那么我们在$[j, a[i][j] + j - 1]$这段区间里面查找最大值(也就是符合条件的最大的$k$)更新答案即可。
注意分奇偶讨论
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define fi first
#define se second
#define MP make_pair
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R
typedef pair <int, int> PII;
const int N = 2010;
char s[N][N];
int fd[N][N], fl[N][N], fr[N][N], a[N][N], b[N][N];
int n, m, now;
int t[N << 4];
int cnt, mx, ans = 0;
PII c[N];
inline void pushup(int i){ t[i] = max(t[i << 1], t[i << 1 | 1]); }
void update(int i, int L, int R, int x, int val){
if (L == R && L == x){
t[i] = max(t[i], val);
return;
}
int mid = (L + R) >> 1;
if (x <= mid) update(lson, x, val);
else update(rson, x, val);
pushup(i);
}
int query(int i, int L, int R, int l, int r){
if (l <= L && R <= r) return t[i];
int mid = (L + R) >> 1;
if (r <= mid) return query(lson, l, r);
else if (l > mid) return query(rson, l, r);
else return max(query(lson, l, r), query(rson, l, r));
}
int main(){
scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%s", s[i] + 1);
dec(i, n, 1) rep(j, 1, m){
fd[i][j] = s[i][j] == 'X' ? fd[i + 1][j] + 1 : 0;
fl[i][j] = s[i][j] == 'X' ? fl[i + 1][j - 1] + 1 : 0;
fr[i][j] = s[i][j] == 'X' ? fr[i + 1][j + 1] + 1 : 0;
}
rep(i, 1, n) rep(j, 1, m) a[i][j] = min(fd[i][j], fr[i][j]), b[i][j] = min(fd[i][j], fl[i][j]);
mx = m << 1;
ans = 0;
rep(i, 1, n){
cnt = 0;
for (int j = 1; j <= m; j += 2) if (b[i][j]) c[++cnt] = MP(j - b[i][j] + 1, j);
sort(c + 1, c + cnt + 1);
memset(t, 0, sizeof t);
now = 0;
for (int j = 1; j <= m; j += 2){
if (!a[i][j]) continue;
while (now < cnt){
if (c[now + 1].fi <= j){
++now;
update(1, 1, mx, c[now].se, c[now].se);
if (now >= cnt) break;
}
else break;
}
int et = query(1, 1, mx, j, a[i][j] + j - 1);
ans = max(ans, et - j + 1);
}
cnt = 0;
for (int j = 2; j <= m; j += 2) if (b[i][j]) c[++cnt] = MP(j - b[i][j] + 1, j);
sort(c + 1, c + cnt + 1);
memset(t, 0, sizeof t);
now = 0;
for (int j = 2; j <= m; j += 2){
if (!a[i][j]) continue;
while (now < cnt){
if (c[now + 1].fi <= j){
++now;
update(1, 1, mx, c[now].se, c[now].se);
if (now >= cnt) break;
}
else break;
}
int et = query(1, 1, mx, j, a[i][j] + j - 1);
ans = max(ans, et - j + 1);
}
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号