• 【题解】$test0627 $ 数据读取问题


    题目描述

    (\)


    (\)

    (Solution)

    这题目描述就离谱bushi

    考场翻来覆去读了几遍题没看懂kkkkk

    大概翻译一下题目意思就是:给你一个序列 (d),如果当前读到 (d_i) ,就跳到 (d_i + a_i) ,目标是最后正好跳到 (n + 1) ;对于 (a_i) 可以修改为 (a_i +- y) ,修改代价为 (y(y >= 0)) ;求最小代价。现在有一棵树,对于从根节点到叶子节点的每条链都看做一个序列,求出所有最小代价。

    感谢(mathtt{I})(mathtt{color{red}{makf}}) 给我讲了好几遍这道题,终于明白力!!!

    (\)

    考虑只在序列上做

    (dp[i]) 表示跳到了 (i) 的时候的最小代价

    若当前 (dp[i]) 已知,设 (j = i + a_i) ,则 (dp[j] = min(dp[j], dp[i])) ,因为可以直接跳到,不需要修改 (a_i)

    那么来考虑修改,则 $$dp[j - x] = min(dp[j - x], dp[j] + j - x)$$ $$dp[j + x] = min(dp[j + x], dp[j] + x - j)$$

    于是可以 (O(n^2)) 顺利解决

    (\)

    接下来考虑优化

    先只考虑 (dp[j] = min(dp[j], dp[i] + i - j)) 这一种转移(就是上面写的那个式子,改了一下变量),往后推的和这个差不多

    想把 (O(n^2)) 降为 (O(nlog n))正确做法是在脑子里随便找一种数据结构试试可不可行

    直接给结论:开一颗线段树,在第 (i) 个叶子节点存的是 (tree[i] = dp[i] + i) ,维护最小值

    为什么要存这个?其实很巧妙

    看看上面的转移方程,如果先不考虑取 (min),即 $$dp[j] = dp[i] + i - j$$

    得到了 (dp[j]) 后我们要存进线段树中,将方程两边加上 (j) 就变成了 $$tree[j] = dp[j] + j = dp[i] + i - j + j = dp[i] + i = tree[i]$$

    发现直接可以用线段树中的 (tree[i]) 更新 (tree[j])

    (\)

    考虑更新的顺序

    由于每个点只能往后跳,所以可以直接按照序列顺序更新

    简单证明:若现在已经更新到了 (i) ,假设点 (j > i) ,若想用 (j + a_j) 更新 (i) ,相当于把 (a_j) 更改为 (i - j) ,而 (a_j) 不可能是负的,所以无法更新

    (\)

    考虑在树上做

    直接深搜,维护一个线段树,在回溯时撤销操作即可

    多写一句关于在树上维护某个数据结构进行撤销操作怎么做

    以下所有原数组指的是全局变量的数据结构

    (1.) 直接开一个数组存下这个原数组,再把原数组进行更新,最后再把这个数组的值赋给原数组

    (2.) 对于树状数组/线段树,如果是单点修改,那就最多只有 (log n) 个点更改,保存这些点即可

    (3.) 对于树状数组/线段树,如果是单点修改,可以直接存下在原数组里这个点的值,撤销就用这个值修改一下(比如说在这个点上 (+3) ,撤销就在这个点上 (-3)

    (\)

    完结撒花✿✿ヽ(°▽°)ノ✿

    (update(2020.7.2):) 关于线段树中到了叶子节点直接赋值而不用取 (min) ,是因为在修改之前就判断了是否大于当前的值,所以一定要修改。被踩辣 (kk)

    (\)


    (\)

    (Code)

    #include<bits/stdc++.h>
    #define mid (l + r >> 1)
    #define ls (k << 1)
    #define rs (k << 1| 1)
    #define F(i, x, y) for(int i = x; i <= y; ++ i)
    using namespace std;
    int read();
    const int N = 1e6 + 5;
    const int inf = 0x3f3f3f3f;
    int n, x, y, m;
    int a[N], ans[N], dp[N], tree[2][N << 2];
    int head[N], cnt, ver[N << 1], nxt[N << 1];
    void add(int x, int y){ver[++ cnt] = y, nxt[cnt] = head[x], head[x] = cnt;}
    void update(int l, int r, int k, int pos, int v, int op)
    {
    	if(l == r && l == pos) {tree[op][k] = v; return;}
    	if(pos <= mid) update(l, mid, ls, pos, v, op);
    	else update(mid + 1, r, rs, pos, v, op);
    	tree[op][k] = min(tree[op][ls], tree[op][rs]);
    }
    int query(int l, int r, int k, int x, int y, int op)
    {
    	if(l >= x && r <= y) return tree[op][k];
    	int res = inf; 
    	if(x <= mid) res = min(res, query(l, mid, ls, x, y, op));
    	if(y > mid) res = min(res, query(mid + 1, r, rs, x, y, op));
    	return res;
    }
    void dfs(int x, int dep)
    {
    	int tmp1 = -inf, tmp2 = -inf, u = a[x] + dep, now = dp[dep - 1] + 1;
    	if(x != 1)
    	{
    		int b1 = query(1, n, 1, u, u, 0), b2 = query(1, n, 1, u, u, 1);
    		if(b1 > now - u) tmp1 = b1, update(1, n, 1, u, now - u, 0);
    		if(b2 > now + u) tmp2 = b2, update(1, n, 1, u, now + u, 1);
    		dp[dep] = min(query(1, n, 1, 1, dep, 0) + dep, query(1, n, 1, dep, n, 1) - dep);
    	}
    	for(int i = head[x]; i; i = nxt[i]) dfs(ver[i], dep + 1);
    	if(! head[x]) ans[++ m] = dp[dep];
    	if(tmp1 != -inf) update(1, n, 1, u, tmp1, 0);
    	if(tmp2 != -inf) update(1, n, 1, u, tmp2, 1);
    }
    int main()
    {
    	n = read();
    	F(i, 1, n) 
    	{
    		a[i] = read(), y = read();
    		F(j, 1, y) x = read(), add(i, x);
    	}
    	memset(tree, 0x3f, sizeof(tree));
    	dfs(1, 1), sort(ans + 1, ans + m + 1);
    	F(i, 1, m) printf("%d
    ", ans[i]);
    	return 0;
    }
    int read()
    {
    	int x = 0, f = 1;
    	char c = getchar();
    	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * f;
    }
    
  • 相关阅读:
    HTTP
    nginx反向代理和负载均衡
    keepalive
    lnmp
    DNS
    jumpserver跳板机
    博客已搬家到CSDN
    JAVA中关于上传图片到数据库和从数据库取出显示图片的问题
    checkbox的标签和全选中问题
    SOCKET
  • 原文地址:https://www.cnblogs.com/Bn_ff/p/13203529.html
Copyright © 2020-2023  润新知