【题解】LuoGu6007:[USACO20JAN]Springboards G

原题传送门
显然可以枚举提到过的点
若一个点 i i ,是一个跳板的终点,那么 d p i = d p j ( j ) dp_i=dp_j(j是该跳板的起点)
一般地,有 d p i = m i n ( d p j + d i s ( i , j ) ) ( d i s ( i , j ) = x i + y i x j y j ) dp_i=min(dp_j+dis(i,j))(dis(i,j)=x_i+y_i-x_j-y_j)
这是个 O ( n 2 ) O(n^2) 的暴力
如何优化

可以按照 x x 为第一关键字 y y 为第二关键字排序
保证 x x 升序,所以接下来只用管 y y 的大小关系
d i s i = x i + y i dis_i=x_i+y_i
用树状数组用 d p i d i s i dp_i-dis_i 更新区间 [ y i , n ] [y_i,n] 的最小值
每次 d p i = q u e r y ( y i ) + d i s i dp_i=query(y_i)+dis_i

可是 y i y_i 1 e 9 1e9 的级别,所以要离散化

Code:

#include <bits/stdc++.h>
#define maxn 200010
#define LL long long
using namespace std;
struct data{
	int x, y, id, opt, dis;
}a[maxn];
int tot, tot1, p, b[maxn], c[maxn], n, m, pos[maxn];
LL tree[maxn], dp[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

bool cmp(data x, data y){ return x.x == y.x ? (x.y == y.y ? x.opt < y.opt : x.y < y.y) : x.x < y.x; }
int lowbit(int x){ return x & -x; }
void update(int x, LL y){ for (; x <= p; x += lowbit(x)) tree[x] = min(tree[x], y); }
LL query(int x){ LL s = 1e9; for (; x; x -= lowbit(x)) s = min(s, tree[x]); return s; }

int find(int x){
	int l = 1, r = p, ans;
	while (l <= r){
		int mid = (l + r) >> 1;
		if (c[mid] == x) return mid;
		else if (c[mid] > x) r = mid - 1; else l = mid + 1;
	}
}

int main(){
	n = read(), m = read();
	for (int i = 1; i <= m; ++i){
		a[++tot].x = read(), a[tot].y = read(), a[tot].opt = 0, a[tot].id = i, a[tot].dis = a[tot].x + a[tot].y;
		a[++tot].x = read(), a[tot].y = read(), a[tot].opt = 1, a[tot].id = i, a[tot].dis = a[tot].x + a[tot].y;
		b[++tot1] = a[tot - 1].y, b[++tot1] = a[tot].y;
	}
	sort(b + 1, b + 1 + tot1);
	b[0] = b[1] - 1;
	for (int i = 1; i <= tot1; ++i)
		if (b[i] != b[i - 1]) c[++p] = b[i], tree[p] = 1e10;
	sort(a + 1, a + 1 + tot, cmp);
	for (int i = 1; i <= tot; ++i) a[i].y = find(a[i].y);
	update(1, 0);
	LL ans = 1e10;
	for (int i = 1; i <= tot; ++i){
		if (!a[i].opt) pos[a[i].id] = i;
		dp[i] = 1e10;
		if (a[i].opt == 1) dp[i] = min(dp[i], dp[pos[a[i].id]]);
		dp[i] = min(dp[i], query(a[i].y) + a[i].dis);
		update(a[i].y, dp[i] - a[i].dis);
		ans = min(ans, dp[i] - a[i].dis);
	}
	printf("%lld\n", ans + n + n);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/108429341
G
今日推荐