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
", ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/cxhscst2/p/7953671.html