当前位置: 首页 > news >正文

[Rust学习:二]变量和传参

[Rust学习:二]变量和传参

    • 一、前言
    • 二、练习
      • 1. 前置:a:&T、a:&mut T、mut a:&T、mut a:&mut T的区别
      • 2. 例题: F - LIS on Tree
      • 3. 题解。
    • 三、 代码实现
    • 六、参考链接

一、前言

  • 在本文通过写一题实战,初步探索了这些技能:
    1. Cargo.toml引入库的配置
    2. main中使用外部库:proconio、itertools、superslice。
    3. 函数声明的形参实参写法以及注意点。
    4. 如何方便的读入(proconio::input!)。
    5. 如何方便的数组join(引入itertools::Itertools后ans.iter().join(“\n”))。
    6. 有序数组的二分查找(引入superslice::Ext后dp.lower_bound(&x))。
    7. 基础整型使用(优先usize吧)。
  • Rust的变量、传参、权限控制真的反人类。
  • 碎碎念:
    1. 实现时通常会使用数组下标作为特征,如:a是点权数组,点化作0~n-1下标来索引点权,这就导致了点的类型必须是usize。那么负值
      就不能用,导致dfs初始fa参数反习惯,很难受。
    2. 后来复盘代码发现很多行尾忘记写分号,也过了,观察了一下发现基本都是代码块的末行,如大括号{}内最后一行。
      这是因为末行如果不写分号默认会帮你把这个表达式作为return的值。

在这里插入图片描述

二、练习

1. 前置:a:&T、a:&mut T、mut a:&T、mut a:&mut T的区别

  • a:&T:引用不可变,且引用指向的内容不可修改。
  • a:&mut T:引用不可变,引用指向的内容可修改。
  • mut a:&T:引用可变(a可重新赋值),但引用指向的内容不可修改。
  • mut a:&mut T:引用可变,引用指向的内容可修改。

2. 例题: F - LIS on Tree

F - LIS on Tree

https://atcoder.jp/contests/abc165/tasks/abc165_f

输入 n (2≤n≤2e5) 和长为 n 的数组 a (1≤a[i]≤1e9),表示每个节点的点权。
然后输入一棵树的 n-1 条边(节点编号从 1 开始)。
输出 n 个数,第 i 个数为从节点 1 到节点 i 的路径上点权的 LIS 长度。

注:LIS 指最长上升子序列。
输入
10
1 2 5 3 4 6 7 3 2 4
1 2
2 3
3 4
4 5
3 6
6 7
1 8
8 9
9 10
输出
1
2
3
3
4
4
5
2
2
3

这是一道atc上的题,题意比较清楚,写个DFS在路径上跑LIS即可。

3. 题解。

  • 我们套用LIS的二分优化模板,需要一个单调递增的dp数组:
    let mut dp: Vec<usize> = vec![0; 0];
    注意这里需要声明dp是mut,后边的vec!宏可以直接创建一个内容是全是0且长度为0的vector。
  • 建图时,本题无边权有点权,因此可以两层int的vector即可:
    let mut g = vec![Vec::new(); n]; 这里省略了g的类型声明。
  • 读入时,使用input!宏,这个宏在proconio包中,注意加入Cargo.toml。
    Cargo.toml:
    [dependencies]
    proconio = "0.4.2"
    
    main.rs:
    use proconio::input;
    input! {
        n:usize,
        a:[usize;n],
        es:[(usize,usize);n-1]
    }
    
  • 输出时,由于要输出n行答案,实测用回车拼完一起输出会快很多。这里需要用到use itertools::Itertools;这个库,注意加Cargo.toml:itertools = "0.10.0"
    main.rs: println!("{}", ans.iter().join("\n"));
  • 注意,vector原来不支持二分,需要引入一个库:use superslice::Ext;,Cargo.toml:superslice = "1.0.0";, main.rs:p = dp.lower_bound(&x);

  • 准备工作做好了接下来是最烦的dfs函数编写。
  • rust的fn支持写在main外边或里边,目前没看出什么区别。即使写在里边也用不了main里的变量,需要显式传参。
  • 为了运行速度,显然所有非基础类型(比如集合等)都要传引用&。坑就在这些地方。
  • 来看函数头:
     fn dfs(
        u: usize,  // 当前节点
        fa: usize,  // 父节点
        g: &Vec<Vec<usize>>,  // 图
        dp: &mut Vec<usize>,  // dp
        ans: &mut Vec<usize>,  // 答案
        a: &Vec<usize>, // 点权
    ) {}
    
    • 其中u和fa是基础类型,函数体内也不会变,直接传值即可。这里fa我在其他语言里一般初始传-1,但是这里必须是usize,因此要传入一个不会存在的节点。由于节点被我转化成0~n-1,因此初始传n以上即可。
    • g是不会变的图,用来dfs路径,因此形参直接声明引用。
    • dp是会变的,大小变push、pop和内容修改。因此形参要声明为&mut Vec<usize>
    • ans同dp。
    • a是用来查询点权,又不变,声明引用即可。
  • 当main里进dfs时,所有实参要显式的传递引用即:
    main:
    dfs(0, 2000000, &g, &mut dp, &mut ans, &a);
    
  • 但在dfs内部自我调用时,由于这些参数本身传进来已经是引用了,因此不加&标志,即:
    dfs:
    dfs(v, u, g, dp, ans, a);
    

三、 代码实现

  • 实现时,由于dfs需要回溯,我使用x变量来储存修改的dp[p]的值,这里可以使用std::mem::swap(&mut x,&mut dp[p]);这个方法,它不会初始化双方的绑定。
/***
https://atcoder.jp/contests/abc165/tasks/abc165_f

输入 n (2≤n≤2e5) 和长为 n 的数组 a (1≤a[i]≤1e9),表示每个节点的点权。
然后输入一棵树的 n-1 条边(节点编号从 1 开始)。
输出 n 个数,第 i 个数为从节点 1 到节点 i 的路径上点权的 LIS 长度。

注:LIS 指最长上升子序列。
输入
10
1 2 5 3 4 6 7 3 2 4
1 2
2 3
3 4
4 5
3 6
6 7
1 8
8 9
9 10
输出
1
2
3
3
4
4
5
2
2
3
 */
use proconio::input;
// use std::collections::VecDeque;
//
use itertools::Itertools;
// use petgraph::{Graph, data::Build};
use superslice::Ext;
const MOD:usize = 1000000000+7;
const INF:usize = 1<<60;
fn main() {
    input!{
        n:usize,
        a:[usize;n],
        es:[(usize,usize);n-1]
    }
    let mut g = vec![Vec::new();n];
    for (u,v) in es {
        g[u-1].push(v-1);
        g[v-1].push(u-1);
    }
    let mut dp:Vec<usize> = vec![0;0];
    // let mut dp:Vec<usize> = vec![INF;n];

    fn dfs(
        u:usize,
        fa:usize,
        g:&Vec<Vec<usize> >,
        dp: &mut Vec<usize>,
        ans:&mut Vec<usize>,
        a: &Vec<usize>
    ){
        let mut x = a[u];
        let  p ;
        if dp.len() == 0 || x>dp[dp.len()-1] {
            dp.push(x);
            p = a.len();
        }
        else {
            p =  dp.lower_bound(&x);
            // let t = x;
            // x = dp[p];
            // dp[p] = t;
            std::mem::swap(&mut x,&mut dp[p]);
        }
        // ans[u] = dp.lower_bound(&INF);
        ans[u] = dp.len();;
        for &v in g[u].iter(){
            if v != fa{
                dfs(v,u,g,dp,ans,a);
            }
        }
        if p == a.len() {
            dp.pop();
        }
        else {
            dp[p] = x;
        }
    }

    let mut ans = vec![1usize;n];
    dfs(0,2000000,&g,&mut dp,&mut ans,&a);
    // for v in ans {
    //     println!("{}",v)
    // }
    println!("{}", ans.iter().join("\n"));
}

六、参考链接

  • https://atcoder.jp/contests/abc165/submissions/36201793

相关文章:

  • 计算机网络-网络层(网络层功能概述,异构网络互联,路由与转发,SDN基本概念)
  • Pandas数据处理可视化
  • 部署项目时常用的Linux命令
  • Jdk8到jdk11 踩坑指南
  • Python 算法设计(2) - 大数运算 - 基于字符串的数字运算和进位
  • 欢迎女神科学家颜宁回国,并祝她如愿以偿
  • Day2:字符串变量,强制类型转化,运算符
  • Linux文件操作系统接口的学习使用
  • 为什么C语言执行效率高,运行快?
  • springboot多模块扫包中的@SpringBootApplication、@ComponentScan和@MapperScan问题
  • 52_Pandas处理日期和时间列(字符串转换、日期提取等)
  • html实现个人空间(源码)
  • 使用插值法公式组成数字电路进行计算的计算机
  • 【javaEE】多线程初阶(Part8线程池!!!)【重要】
  • 【Leetcode每日一题:1106.解析布尔表达式~~~栈+模拟+计数+位运算】
  • 【译】JS基础算法脚本:字符串结尾
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • Angular 响应式表单之下拉框
  • es6要点
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Java程序员幽默爆笑锦集
  • linux学习笔记
  • ubuntu 下nginx安装 并支持https协议
  • 成为一名优秀的Developer的书单
  • 对超线程几个不同角度的解释
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 前端自动化解决方案
  • 设计模式(12)迭代器模式(讲解+应用)
  • 使用API自动生成工具优化前端工作流
  • 以太坊客户端Geth命令参数详解
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • 阿里云ACE认证学习知识点梳理
  • # 数据结构
  • #stm32驱动外设模块总结w5500模块
  • ( 10 )MySQL中的外键
  • (windows2012共享文件夹和防火墙设置
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • (转载)虚函数剖析
  • .mysql secret在哪_MYSQL基本操作(上)
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • @Bean有哪些属性
  • @ModelAttribute 注解
  • @ModelAttribute注解使用
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [《百万宝贝》观后]To be or not to be?
  • [ASP]青辰网络考试管理系统NES X3.5
  • [AutoSar NVM] 存储架构
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [CodeForces-759D]Bacterial Melee
  • [E单调栈] lc2487. 从链表中移除节点(单调栈+递归+反转链表+多思路)
  • [Interview]Java 面试宝典系列之 Java 多线程
  • [Java] 什么是IoC?什么是DI?它们的区别是什么?
  • [Linux] MySQL数据库之索引