【LOJ6411】「ICPC World Finals 2018」三角形

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/88722199

【题目链接】

【思路要点】

  • 不失一般性地,我们考虑计算倒三角的个数。
  • 考虑枚举其靠下的顶点 ( x , y ) (x,y) ,记其向左斜向上的边最长长度为 l x , y l_{x,y} ,向右斜向上的边最长长度为 r x , y r_{x,y} ,那么该顶点处至多产生 M i n { l x , y , r x , y } Min\{l_{x,y},r_{x,y}\} 个三角形,其靠上方的一条边所在的行可能是 x , x 1 , x 2 , . . . , x M i n { l x , y , r x , y } + 1 x,x-1,x-2,...,x-Min\{l_{x,y},r_{x,y}\}+1 ,我们还需要检测这些行对应的区间是否被边填满。
  • 考虑同时处理靠右侧的边在一条直线上的顶点 ( x , y ) (x,y) ,那么某一行 x x 产生贡献的行将是 x x 开始的若干行,取决于其左侧边最长的长度,可以直接用树状数组维护行的贡献,并区间询问贡献。
  • 时间复杂度 O ( N M L o g N ) O(NMLogN)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 6005;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct BinaryIndexTree {
	int n, a[MAXN];
	void init(int x) {
		n = x;
		memset(a, 0, sizeof(a));
	}
	void modify(int x, int d) {
		for (int i = x; i <= n; i += i & -i)
			a[i] += d;
	}
	int query(int x) {
		int ans = 0;
		for (int i = x; i >= 1; i -= i & -i)
			ans += a[i];
		return ans;
	}
	int query(int l, int r) {
		int ans = 0;
		for (int i = r; i >= 1; i -= i & -i)
			ans += a[i];
		for (int i = l - 1; i >= 1; i -= i & -i)
			ans -= a[i];
		return ans;
	}
} BIT;
char s[MAXN][MAXN * 2]; vector <int> q[MAXN];
int n, m, l[MAXN / 2][MAXN], r[MAXN / 2][MAXN], len[MAXN / 2][MAXN];
ll getans(int delta) {
	for (int i = 1; i <= m; i++)
		l[1][i] = r[1][i] = 1;
	ll ans = 0;
	for (int j = 1; j <= m; j++) {
		if ((1 + j + delta) & 1) continue;
		if (j >= 2 && s[1 * 2 - 1][(j - 1) * 2 - 1] == '-') len[1][j] = len[1][j - 2] + 1; 
		else len[1][j] = 0;
	}
	for (int i = 2, now = 0, from = 1; i <= n; i++, swap(now, from)) {
		for (int j = 1; j <= m; j++) {
			if ((i + j + delta) & 1) continue;
			if (j >= 2 && s[i * 2 - 1][(j - 1) * 2 - 1] == '-') len[i][j] = len[i][j - 2] + 1; 
			else len[i][j] = 0;
			if (s[(i - 1) * 2][(j - 1) * 2] != '\\') l[i][j] = i;
			else l[i][j] = l[i - 1][j - 1];
			if (s[(i - 1) * 2][j * 2] != '/') r[i][j] = i;
			else r[i][j] = r[i - 1][j + 1];
		}
	}
	for (int s = 2; s <= n + m; s++) {
		if ((s + delta) & 1) continue;
		for (int i = 1; i <= n; i++)
			q[i].clear();
		BIT.init(n);
		for (int i = 1; i <= n; i++) {
			int j = s - i;
			if (j < 1 || j > m) continue;
			if (i + len[i][j] + 1 <= n) q[i + len[i][j] + 1].push_back(i);
			for (auto x : q[i])
				BIT.modify(x, -1);
			ans += BIT.query(max(l[i][j], r[i][j]), i);
			BIT.modify(i, 1);
		}
	}
	return ans;
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= 2 * n - 1; i++) {
		int tot = 0; char c = getchar();
		while (c != '\n' && c != -1) {
			s[i][++tot] = c;
			c = getchar();
		}
	}
	ll ans = getans(0);
	for (int i = 1; i <= n; i++)
		swap(s[i], s[2 * n - i]);
	for (int i = 1; i <= 2 * n - 1; i++)
	for (int j = 1; j <= 2 * m - 1; j++)
		if (s[i][j] == '/') s[i][j] = '\\';
		else if (s[i][j] == '\\') s[i][j] = '/';
	ans += getans((n + 1) & 1);
	writeln(ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/88722199