AtCoder Beginner Contest 177 F I hate Shortest Path Problem

洛谷传送门

AtCoder 传送门

\(f_{i,j}\) 为从第 \(1\) 行到 \((i + 1, j)\) 的最短路。

因为我们并不关心最后到达的是哪一个格子,于是强制 \(f_{i,j}\) 为必须从 \((i, j)\) 往下走一格到 \((i + 1, j)\) 的最短路。

有转移:

\[f_{i,r+1} \gets f_{i-1,j} + r + 2 - j, j \in [l, r] \]

\[f_{i,j} \gets f_{i-1,j} + 1, j \notin [l, r] \]

\([l, r]\) 表示第 \(i\) 行被 ban 掉的区间。

这个东西显然能用线段树优化。具体地,枚举到第 \(i\) 行,线段树每个叶子结点 \([j,j]\)\(f_{i,j} - j\) 的最小值。对于第一种转移,区间查最小值,单点修;对于第二种转移,区间加 \(1\)。注意到 \(j \in [l,r], f_{i,j}\) 不合法,把它们加上一个 \(+\infty\) 即可。

时间复杂度线性对数。

code
// Problem: F - I hate Shortest Path Problem
// Contest: AtCoder - AtCoder Beginner Contest 177
// URL: https://atcoder.jp/contests/abc177/tasks/abc177_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;
const ll inf = 0x3f3f3f3f3f3f3f3fLL;

int n, m;
struct node {
	int l, r;
} a[maxn];

namespace SGT {
	ll tree[maxn << 2], tag[maxn << 2], mn[maxn << 2];
	
	inline void pushup(int x) {
		tree[x] = min(tree[x << 1], tree[x << 1 | 1]);
		mn[x] = min(mn[x << 1], mn[x << 1 | 1]);
	}
	
	inline void pushdown(int x) {
		if (!tag[x]) {
			return;
		}
		tree[x << 1] += tag[x];
		tree[x << 1 | 1] += tag[x];
		mn[x << 1] += tag[x];
		mn[x << 1 | 1] += tag[x];
		tag[x << 1] += tag[x];
		tag[x << 1 | 1] += tag[x];
		tag[x] = 0;
	}
	
	void build(int rt, int l, int r) {
		if (l == r) {
			mn[rt] = -l;
			return;
		}
		int mid = (l + r) >> 1;
		build(rt << 1, l, mid);
		build(rt << 1 | 1, mid + 1, r);
		pushup(rt);
	}
	
	void update(int rt, int l, int r, int ql, int qr, int x) {
		if (ql > qr) {
			return;
		}
		if (ql <= l && r <= qr) {
			tree[rt] += x;
			mn[rt] += x;
			tag[rt] += x;
			return;
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if (ql <= mid) {
			update(rt << 1, l, mid, ql, qr, x);
		}
		if (qr > mid) {
			update(rt << 1 | 1, mid + 1, r, ql, qr, x);
		}
		pushup(rt);
	}
	
	void modify(int rt, int l, int r, int x, ll y) {
		if (l == r) {
			tree[rt] = min(tree[rt], y);
			mn[rt] = min(mn[rt], y - l);
			return;
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		(x <= mid) ? modify(rt << 1, l, mid, x, y) : modify(rt << 1 | 1, mid + 1, r, x, y);
		pushup(rt);
	}
	
	ll query(int rt, int l, int r, int ql, int qr) {
		if (ql <= l && r <= qr) {
			return mn[rt];
		}
		pushdown(rt);
		ll mid = (l + r) >> 1, res = inf;
		if (ql <= mid) {
			res = min(res, query(rt << 1, l, mid, ql, qr));
		}
		if (qr > mid) {
			res = min(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
		}
		return res;
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%d%d", &a[i].l, &a[i].r);
	}
	SGT::build(1, 1, m);
	for (int i = 1; i <= n; ++i) {
		int l = a[i].l, r = a[i].r;
		SGT::update(1, 1, m, 1, l - 1, 1);
		SGT::update(1, 1, m, r + 1, m, 1);
		ll t = SGT::query(1, 1, m, l, r);
		SGT::update(1, 1, m, l, r, 2e9);
		if (r < m) {
			SGT::modify(1, 1, m, r + 1, t + r + 2);
		}
		ll res = SGT::tree[1];
		printf("%lld\n", res > 1e9 ? -1 : res);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2023-05-11 21:44  zltzlt  阅读(35)  评论(0)    收藏  举报