1 条题解

  • 0
    @ 2025-8-24 22:16:28

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zhoukangyang
    ^w^/

    搬运于2025-08-24 22:16:28,当前版本为作者最后更新于2020-08-29 13:21:41,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    蒟蒻语

    有神仙让蒟蒻讲思路, 蒟蒻就写了篇题解 qwq

    蒟蒻解

    先将所有坐标的 yy 坐标离散化。

    然后把所有坐标按照 xx 为第一关键字, yy 为第二关键字排序。

    从前往后遍历, 用 dpidp_i 表示从 (0,0)(0, 0)xi,yix_i, y_i 的答案。

    怎么更新信息?

    考虑用 kk 节点更新 ii 节点。

    如果 kk 节点可以直接用跳板直接跳到 ii 节点, 那么 dpdp 值相同。

    否则要一步一步走过去。如果能更新, 那么 dpi=dpk+xixk+yiykdp_i = dp_k + x_i - x_k + y_i - y_k

    那么 dpixiyi=dpkxkykdp_i - x_i - y_i = dp_k - x_k - y_k

    如果设 fi=dpixiyif_i = dp_i - x_i - y_i,那么 fi=fkf_i = f_k !

    那么现在丢掉 dpdp 数组然后使用 ff 数组。

    现在如果kk 节点可以直接用跳板直接跳到 ii 节点

    $f_i = dp_i - x_i - x_j = dp_k - x_i - y_i = f_k + x_k + y_k - x_i - y_i$

    那么考虑谁能够更新他呢?

    只有 xx 坐标小于等于他而且 yy 坐标小于等于他的节点可以更新。

    这时显然 xx 坐标小于等于 ii 节点已经满足, 而 yy 坐标没有满足。 现在要求 yy 坐标处于 0...yi0 ... y_i 的节点。

    fif_imin(f1,2...i1)min(f_{1,2...i-1}) , 显然每次把 ff 值丢进树状数组里面就可以单次 O(logn)O(\log n) 维护了

    如果 ii 是一个跳板的末端, 直接更新一下就好了qwq

    最后答案就是 min(fi+n+n)min(f_i + n + n) (如果把他当作一个节点, 那么 ff 值就是 min(fi)min(f_i), 所以答案是 min(fi+n+n)min(f_i + n + n))

    细节看蒟蒻丑陋的代码吧 qwq

    #include<bits/stdc++.h>
    #define N 200010
    using namespace std;
    int n, m, a[N], fr[N], to[N], Ans;
    struct node {
    	int x, y, yy, id;
    } p[N];
    bool cmp(node aa, node bb) {
    	return aa.x == bb.x ? aa.y < bb.y : aa.x < bb.x;
    }
    bool ycmp(node aa, node bb) {
    	return aa.y < bb.y;
    }
    int ans[N];
    void add(int x, int val) {
    	for(; x <= m * 2; x += (x & -x)) ans[x] = min(ans[x], val);
    } 
    int qzh(int x) {
    	int Ans = 0; 
    	for(; x; x -= (x & -x)) Ans = min(Ans, ans[x]);
    	return Ans;
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i++) {
    		scanf("%d%d", &p[i].x, &p[i].y), p[i].id = i;
    		scanf("%d%d", &p[i + m].x, &p[i + m].y), p[i + m].id = i;
    	}
    	sort(p + 1, p + m * 2 + 1, ycmp);
    	p[0].y = -1;
    	for(int i = 1; i <= 2 * m; i++) p[i].yy = p[i - 1].yy + (p[i - 1].y != p[i].y);
    	sort(p + 1, p + m * 2 + 1, cmp);
    	for(int i = 1; i <= m * 2; i++) {
    		if(fr[p[i].id]) to[p[i].id] = i;
    		else fr[p[i].id] = i;
    	}
    	for(int i = 1; i <= m * 2; i++) {
    		a[i] = min(a[i], qzh(p[i].yy));
    		if(fr[p[i].id] == i) a[to[p[i].id]] = min(a[to[p[i].id]], 
    			a[i] + p[i].x + p[i].y - p[to[p[i].id]].x - p[to[p[i].id]].y);
    		add(p[i].yy, a[i]);
    		Ans = min(Ans, a[i]);
    	}
    	printf("%d\n", Ans + n * 2);
    	return 0;
    }
    
    • 1

    信息

    ID
    5023
    时间
    2000ms
    内存
    250MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者