Loading

MX galaxy Day6

walk

最大值和最小值肯定要划分到同一个集合,设这个集合为 \(A\) ,另一个集合为 \(B\) ,则代价为
\(\max_{b\in B}\{|max-b|, |min-b| \}\) ,则另一个集合越小越优,而边角的那一个点是必选的,只留那一个就好了。
所以答案就是右上角单独一个集合和左下角单独一个集合取更优。

color

分三种情况,两条横的,两条竖的,一横一竖的。
前两种是好做的,现在考虑第三种情况。
枚举横纵延长线的交点,用前后缀优化就好了。

(本人没有写这种做法)

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)

const int _ = 1500 + 7;
typedef long long ll;
typedef std::pair<int, int> PII;

int n, len, ans, st, ed, al[_], ar[_], au[_], ad[_];
int cn, cx, rn, rx;
char s[_][_]; bool c[_][_], r[_][_];

void upd(int x, int& a, int& b) {
	if (x >= a) b = a, a = x;
	else if (x >= b) b = x;
}
void Dwn(int x, int y) {
	if (x == n + 1 or s[x][y] == 'X') return upd(len, cn, cx);
	c[x][y] = true, ++len;
	Dwn(x + 1, y);
}
void Rgh(int x, int y) {
	if (y == n + 1 or s[x][y] == 'X') return ed = y, upd(len, rn, rx);
	r[x][y] = true, ++len;
	Rgh(x, y + 1);
	al[y] = std::max(al[y], y - st + 1), ar[y] = std::max(ar[y], ed - y);
}

int main() {
	scanf("%d", & n);
	lep(i, 1, n) scanf("%s", s[i] + 1);
	lep(i, 1, n) lep(j, 1, n) if (s[i][j] == '.') {
		if (!c[i][j]) len = 0, Dwn(i, j), ans = std::max(ans, len / 2);
		if (!r[i][j]) len = 0, st = j, Rgh(i, j), ans = std::max(ans, len / 2),
			au[i] = std::max(au[i], len), ad[i] = au[i];
	}
	
	ans = std::max(ans, std::min(cn, cx)), ans = std::max(ans, std::min(rn, rx));
	lep(i, 2, n) al[i] = std::max(al[i], al[i - 1]), au[i] = std::max(au[i], au[i - 1]);
	rep(i, n - 1, 1) ar[i] = std::max(ar[i], ar[i + 1]), ad[i] = std::max(ad[i], ad[i + 1]);
	
	lep(i, 1, n) lep(j, 1, n) if (s[i][j] == '.') {
		int R = std::max(std::max(au[i - 1], al[j - 1]), ar[j + 1]);
		lep(k, i, n) {
			if (s[k][j] == 'X') break;
			else ans = std::max(ans, std::min(k - i + 1, std::max(R, ad[k + 1])));
		}
	}
	
	printf("%d\n", ans);
	return 0;
}

orz

我们将同一个人在不同排列中的位置连 \(0\) 边,每个位置向其后缀连 \(1\) 边。
那么我们想要找到 \(x\) 等价类 到 \(y\) 等价类 的最短路。
但是这样转化是完全倒闭的,我们可以对于每个位置 \((i, j)\) 处理出其跳到 \(k\) 列时最靠前的位置。
这样一定是最优的。
但这样复杂度接受不了,我们可以倍增。
具体的,处理出 \(to[i, k, p, j]\) 表示 \((i, j)\) 这个位置跳 \(2^p\) 步到第 \(k\) 行最靠前的位置。
注意 \(\boldsymbol{内存连续性优化}\) ,将 \(j\) 这一维放到最后,可以快 \(5\) 倍左右。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)

const int _ = 2e5 + 7;
typedef long long ll;

int n, m, q, a[5][_], b[5][_], to[5][5][21][_]; //i k p j
int nw[5], tmp[5];

int main() {
	scanf("%d%d", & n, & m);
	lep(i, 0, m - 1) lep(j, 1, n) scanf("%d", a[i] + j), b[i][a[i][j]] = j;
	lep(k, 0, m - 1) lep(i, 0, m - 1) {
		rep(j, n, 1) {
			to[i][k][0][j] = b[k][a[i][j]];
			if (j != n) to[i][k][0][j] = std::min(to[i][k][0][j], to[i][k][0][j + 1]);
		}
	}
	
	lep(p, 1, 20) {
		lep(i, 0, m - 1) lep(k, 0, m - 1) lep(j, 1, n) {
			to[i][k][p][j] = n + 1;
			lep(t, 0, m - 1) to[i][k][p][j] = std::min(to[i][k][p][j], to[t][k][p - 1][to[i][t][p - 1][j]]);
		}
	}
	
	scanf("%d", & q); int x, y;
	while (q--) {
		scanf("%d%d", & x, & y); int ans = 0; bool legal = false;
		lep(i, 0, m - 1) nw[i] = b[i][x];
		lep(i, 0, m - 1) if (nw[i] <= b[i][y]) { puts("1"); legal = true; break; }
		if (legal) continue;
		rep(p, 20, 0) { bool flag = true;
			lep(i, 0, m - 1) {
				tmp[i] = nw[i];
				lep(j, 0, m - 1) tmp[i] = std::min(tmp[i], to[j][i][p][nw[j]]);
				if (tmp[i] <= b[i][y]) { flag = false, legal = true; break; }
			}
			if (flag) {
				if (p == 20) break;
				lep(i, 0, m - 1) nw[i] = tmp[i];
				ans += (1 << p);
			}
		}
		if (legal) printf("%d\n", ans + 2);
		else puts("-1");
	}
	return 0;
}

flight

注意到一条转移路径除了终点外 \(b\) 是单调下降的。
这为我们的转移规定了顺序,我们按照 \(b\) 降序处理,但是路径信息我们很难做,考虑点分树。
推一下式子, \(dp_u = \min\{dp_v + a_v + b_v \times dis(rt, v) + b_v\times dis(rt, u) \}\)
变成了斜率优化的形式,用 李超线段树 维护。
具体的,每考虑到一个点,先用其点分树上的所有祖先更新出答案,再把自己的直线插入祖先中。
但是,终点可能 \(b\) 并不是递减的,再对每一个点查询一遍就好了。
注意到点分树中在同一个子树内一定不优,会被更早的更新掉,所以没有影响。

李超线段树 \(TLE\) 了可以把递归改成迭代。

点击查看

#include <bits/stdc++.h>
std::vector<long long> travel(std::vector<long long> A, std::vector<int> Bi, std::vector<int> U, std::vector<int> V, std::vector<int> W);
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)

const int _ = 1e5 + 7;
typedef long long ll;
const ll inf = 4e18;

int n, pr[_], dep[_], dfn[_], idx, fa[_], st[_][21], lg[_], id[_]; 
ll a[_], b[_], len[_], dp[_];
int sz[_], tmp[_], Rt; bool vis[_];
int seg[_ * 600], ls[_ * 600], rs[_ * 600], tot, cnt, rt[_]; ll K[_ * 20], B[_ * 20];
std::vector <ll> av; int AV;
std::vector <int> e[_], g[_];
std::vector <ll> ans;

void getrt(int u, int f, int total) {
	sz[u] = 1, tmp[u] = 0;
	for (int v : e[u]) if (!vis[v] and v != f)
		getrt(v, u, total), sz[u] += sz[v], tmp[u] = std::max(tmp[u], sz[v]);
	tmp[u] = std::max(tmp[u], total - sz[u]);
	if (!Rt or tmp[u] < tmp[Rt]) Rt = u;
}
int solve(int u, int total) {
	Rt = 0, getrt(u, 0, total), vis[Rt] = true; int t = Rt;
	for (int v : e[Rt]) if (!vis[v]) pr[solve(v, total - tmp[v])] = t;
	return t;
}
void init(int u, int f, ll d) {
	len[u] = d, dep[u] = dep[fa[u] = f] + 1, dfn[u] = ++idx, st[idx][0] = u;
	lep(k, 0, (int)e[u].size() - 1) { int v = e[u][k], w = g[u][k];
		if (v != f) init(v, u, d + w);
	}
}
inline int upd(int x, int y) { return dep[x] < dep[y] ? x : y; }
inline int lca(int x, int y) {
	if (dfn[x] > dfn[y]) std::swap(x, y);
	int k = lg[dfn[y] - dfn[x] + 1], p = upd(st[dfn[x]][k], st[dfn[y] - (1 << k) + 1][k]);
	return p == x ? x : fa[p];
}
inline ll Dis(int x, int y) { return len[x] - 2 * len[lca(x, y)] + len[y]; }
void Init() {
	init(1, 0, 0), solve(1, n);
	lep(j, 1, 20) lep(i, 1, n - (1 << j) + 1)
		st[i][j] = upd(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
	dp[1] = 0;
	lep(i, 2, n) lg[i] = lg[i >> 1] + 1, dp[i] = a[1] + b[1] * Dis(1, i);
	lep(i, 1, n) {
		int j = i;
		while (j) av.push_back(Dis(i, j)), j = pr[j];
	}
	std::sort(av.begin(), av.end()), av.erase(std::unique(av.begin(), av.end()), av.end()); AV = av.size();
}
inline ll Val(int x, int d) { return K[x] * av[d - 1] + B[x]; }
inline int upd(int x, int y, int d) { return (!x or !y) ? (x | y) : Val(x, d) < Val(y, d) ? x : y; }
#define md ((s + t) >> 1)
void mdy(int s, int t, int v, int* p) {
	while (true) {
		if (!v) break; if (!*p) *p = ++tot; int& u = seg[*p];
		if (upd(u, v, md) == v) std::swap(u, v);
		if (s == t or !v) break;
		if (upd(u, v, s) == v) t = md, p = &ls[*p];
		else if (upd(u, v, t) == v) s = md + 1, p = &rs[*p];
		else break;
	}
}
int qry(int s, int t, int d, int p) { int res = 0;
	while (true) {
		if (!seg[p]) break;
		res = upd(res, seg[p], d);
		if (s == t) break;
		d <= md ? (t = md, p = ls[p]) : (s = md + 1, p = rs[p]);
	}
	return res;
}
#undef md
void Ins(int x, int u) {
	K[++cnt] = b[u], B[cnt] = a[u] + dp[u] + b[u] * Dis(x, u);
	mdy(1, AV, cnt, &rt[x]);
}
inline int ID(ll x) { return std::lower_bound(av.begin(), av.end(), x) - av.begin() + 1; }
ll Calc(int x, int u) { int p = ID(Dis(x, u)); return Val(qry(1, AV, p, rt[x]), p); }

std::vector<long long> travel(std::vector<long long> A, std::vector<int> Bi, std::vector<int> U, std::vector<int> V, std::vector<int> W) {
	n = A.size(); int u, v, w; B[0] = inf;
	lep(i, 1, n) a[i] = A[i - 1], b[i] = Bi[i - 1], id[i] = i;
	dp[1] = 0;
	lep(i, 2, n) u = U[i - 2], v = V[i - 2], w = W[i - 2], ++u, ++v,
		e[u].push_back(v), g[u].push_back(w), e[v].push_back(u), g[v].push_back(w);
	Init();
	std::sort(id + 1, id + 1 + n, [](const int&x, const int&y) { return b[x] > b[y]; });
	lep(j, 1, n) { u = id[j], v = u;
		while (v) dp[u] = std::min(dp[u], Calc(v, u)), v = pr[v];
		v = u;
		while (v) Ins(v, u), v = pr[v];
	}
	lep(j, 1, n) { u = id[j], v = u;
		while (v) dp[u] = std::min(dp[u], Calc(v, u)), v = pr[v];
	}

	lep(i, 2, n) ans.push_back(dp[i]);
	return ans;
}


posted @ 2025-07-20 19:16  qkhm  阅读(8)  评论(0)    收藏  举报