C++: 使用 LCT 算法做这道题:A+B Problem/n/n## 题目背景/n/n强烈推荐'新用户必读帖'(/discuss/show/241461)。/n/n不熟悉算法竞赛的选手请看这里:/n/n算法竞赛中要求的输出格式中,'不能有多余的内容','这也包括了“请输入整数 a 和 b” 这一类的提示用户输入信息的内容'。若包含了这些内容,将会被认为是 Wrong Answer,即洛谷上的 WA。在对比代码输出和标准输出时,系统将忽略每一行结尾的空格,以及最后一行之后多余的换行符。/n/n若因此类问题出现本机(看起来)AC,提交 WA 的现象,请勿认为是洛谷评测机出了问题,而是你的代码中可能存在多余的输出信息。用户可以参考在题目末尾提供的代码。/n/n另外'请善用应用中的在线 IDE 功能',以避免不同平台的评测中所产生的一些问题。/n/n还有一点很重要的是,请不要在对应的题目讨论区中发布自己的题解,请发布到题解区域中,否则将处以删除或禁言的处罚。若发现无法提交题解则表明本题题解数量过多,仍不应发布讨论。/n/n## 题目描述/n/n输入两个整数 a, b,输出它们的和(|a|,|b| ≤ 10^9)。/n/n注意/n/n1. Pascal 使用 integer 会爆掉哦!/n2. 有负数哦!/n3. C/C++ 的 main 函数必须是 int 类型,而且 C 最后要 return 0。这不仅对洛谷其他题目有效,而且也是 NOIP/CSP/NOI 比赛的要求!/n/n好吧,同志们,我们就从这一题开始,向着大牛的路进发。/n/n> 任何一个伟大的思想,都有一个微不足道的开始。/n/n## 输入格式/n/n两个以空格分开的整数。/n/n## 输出格式/n/n一个整数。/n/n## 样例 #1/n/n### 样例输入 #1/n/n/n20 30/n/n/n### 样例输出 #1/n/n/n50/n/n/n## 提示/n/n广告/n/n洛谷出品的算法教材,帮助您更简单的学习基础算法。'【官方网店绝赞热卖中!】>>>'(https://item.taobao.com/item.htm?id=637730514783)/n/n/n/n本题各种语言的程序范例:/n/nC/nc/n#include <stdio.h>/n/nint main()/n{/n int a,b;/n scanf(/'%d%d',&a,&b);/n printf(/'%d//n/', a+b);/n return 0;/n}/n/n----------------/n/nC++/ncpp/n#include <iostream>/n#include <cstdio>/n/nusing namespace std;/n/nint main()/n{/n int a,b;/n cin >> a >> b;/n cout << a+b << endl;/n return 0;/n}/n/n----------------/n/nPascal/ncpp/nvar a, b: longint;/nbegin/n readln(a,b);/n writeln(a+b);/nend./n/n-----------------/n/nPython2/n/ncpp/ns = raw_input().split()/nprint int(s[0]) + int(s[1])/n/n-----------------/n/nPython3/n/ncpp/ns = input().split()/nprint(int(s[0]) + int(s[1]))/n/n-----------------/n/nJava/njava/nimport java.io.*;/nimport java.util.*;/npublic class Main {/n public static void main(String args[]) throws Exception {/n Scanner cin=new Scanner(System.in);/n int a = cin.nextInt(), b = cin.nextInt();/n System.out.println(a+b);/n }/n}/n/n-----------------/n/nJavaScript (Node.js)/n/njavascript/nconst fs = require('fs')/nconst data = fs.readFileSync('/dev/stdin')/nconst result = data.toString('ascii').trim().split(' ').map(x => parseInt(x)).reduce((a, b) => a + b, 0)/nconsole.log(result)/nprocess.exit() // 请注意必须在出口点处加入此行/n/n/n-----------------/n/nRuby/n/nruby/na, b = gets.split.map(&:to_i)/nprint a+b/n/n/n-----------------/n/nPHP/n/nphp/n<?php/n$input = trim(file_get_contents(/'php://stdin/'));/nlist($a, $b) = explode(' ', $input);/necho $a + $b;/n/n/n-----------------/n/nRust/n/nrust/nuse std::io;/n/nfn main(){/n let mut input=String::new();/n io::stdin().read_line(&mut input).unwrap();/n let mut s=input.trim().split(' ');/n/n let a:i32=s.next().unwrap()/n .parse().unwrap();/n let b:i32=s.next().unwrap()/n .parse().unwrap();/n println!('{}',a+b);/n}/n/n/n-----------------/n/nGo/n/ngo/npackage main/n/nimport /'fmt/'/n/nfunc main() {/n var a, b int/n fmt.Scanf(/'%d%d/', &a, &b)/n fmt.Println(a+b)/n}/n/n/n-----------------/n/nC# Mono/n/ncs/nusing System;/n/npublic class APlusB{/n private static void Main(){/n string[] input = Console.ReadLine().Split(' ');/n Console.WriteLine(int.Parse(input[0]) + int.Parse(input[1]));/n }/n}/n/n/n------------------/n/nVisual Basic Mono/n/nvb/nImports System/n/nModule APlusB/n Sub Main()/n Dim ins As String() = Console.ReadLine().Split(New Char(){/' /'c})/n Console.WriteLine(Int(ins(0))+Int(ins(1)))/n End Sub/nEnd Module/n/n/n------------------/n/nKotlin/n/nkotlin/nfun main(args: Array<String>) {/n val (a, b) = readLine()!!.split(' ').map(String::toInt)/n println(a + b)/n}/n/n/n------------------/n/nHaskell/n/nhaskell/nmain = do/n [a, b] <- (map read . words) `fmap` getLine/n print (a+b)/n/n/n------------------/n/nScala/n/nscala/nobject Main extends App {/n println(scala.io.StdIn.readLine().split(/' /').map(_.toInt).sum)/n}/n/n/n------------------/n/nPerl/n/nperl/nmy $in = <STDIN>;/nchomp $in;/n$in = [split /[/s,]+/, $in];/nmy $c = $in->[0] + $in->[1];/nprint /'$c//n/';/n/n/n------------------/n/n## LCT 算法详解/n/n### 1. 简介/n/nLCT(Link-Cut Tree,链式剖分树)是一种用来维护动态树的算法,它能够高效地解决以下问题:/n/n1. 动态树的连通性查询/n2. 动态树路径上的信息维护(例如路径上的最大值、最小值、和等)/n3. 动态树的修改操作(例如修改节点的值、断开连接、连接节点等)/n/nLCT 算法的核心思想是将树分解成若干条链,并用 Splay Tree 来维护这些链。每个节点都属于一条链的顶端,并且链上的所有节点都是 Splay Tree 的一个节点。/n/n### 2. 算法实现/n/ncpp/n#include <iostream>/n#include <vector>/n#include <algorithm>/n/nusing namespace std;/n/n// 定义节点结构体/nstruct Node {/n int val; // 节点的值/n int sum; // 节点及其子树的和/n int lazy; // 懒惰标记,用来标记该节点是否进行了翻转操作/n int size; // 节点的大小,即节点及其子树的节点个数/n Node *fa; // 父节点指针/n Node *ch[2]; // 左右孩子指针/n/n Node() {/n val = sum = lazy = size = 0;/n fa = ch[0] = ch[1] = nullptr;/n }/n};/n/n// 获取节点的大小/nint getSize(Node *x) {/n return x ? x->size : 0;/n}/n/n// 更新节点的信息/nvoid update(Node *x) {/n if (x) {/n x->size = getSize(x->ch[0]) + getSize(x->ch[1]) + 1;/n x->sum = (x->val) + (x->ch[0] ? x->ch[0]->sum : 0) + (x->ch[1] ? x->ch[1]->sum : 0);/n }/n}/n/n// 修改节点的懒惰标记/nvoid reverse(Node *x) {/n if (x) {/n x->lazy ^= 1;/n swap(x->ch[0], x->ch[1]);/n }/n}/n/n// 下传懒惰标记/nvoid pushdown(Node *x) {/n if (x && x->lazy) {/n reverse(x->ch[0]);/n reverse(x->ch[1]);/n x->lazy = 0;/n }/n}/n/n// 判断节点是否为其父节点的左孩子/nint getDir(Node *x) {/n return x->fa && x->fa->ch[1] == x;/n}/n/n// 旋转操作/nvoid rotate(Node *x) {/n Node *y = x->fa;/n Node *z = y->fa;/n int d1 = getDir(x);/n int d2 = getDir(y);/n Node *p = x->ch[d1 ^ 1];/n/n y->ch[d1] = p;/n if (p)/n p->fa = y;/n x->ch[d1 ^ 1] = y;/n y->fa = x;/n x->fa = z;/n if (z)/n z->ch[d2] = x;/n/n update(y);/n update(x);/n}/n/n// 伸展操作/nvoid splay(Node *x) {/n while (x->fa) {/n Node *y = x->fa;/n Node *z = y->fa;/n if (z)/n pushdown(z);/n pushdown(y);/n pushdown(x);/n if (z) {/n if (getDir(x) == getDir(y)) {/n rotate(y);/n } else {/n rotate(x);/n }/n }/n rotate(x);/n }/n}/n/n// 获取根节点/nNode *access(Node *x) {/n Node *y = nullptr;/n for (; x; y = x, x = x->fa) {/n splay(x);/n x->ch[1] = y;/n update(x);/n }/n return y;/n}/n/n// 将x节点设置为根节点/nvoid makeRoot(Node *x) {/n access(x);/n splay(x);/n reverse(x);/n}/n/n// 将x节点和y节点连接/nvoid link(Node *x, Node *y) {/n makeRoot(x);/n x->fa = y;/n}/n/n// 将x节点和y节点断开/nvoid cut(Node *x, Node *y) {/n makeRoot(x);/n access(y);/n splay(y);/n y->ch[0] = x->fa = nullptr;/n update(y);/n}/n/n// 查询x节点所在的树的和/nint query(Node *x) {/n access(x);/n splay(x);/n return x->sum;/n}/n/n// 修改x节点的值/nvoid updateValue(Node *x, int v) {/n access(x);/n splay(x);/n x->val = v;/n update(x);/n}/n/nint main() {/n int a, b;/n cin >> a >> b;/n cout << (a + b) << endl;/n return 0;/n}/n/n/n### 3. 代码解析/n/n1. 节点结构体:/n * val: 节点的值/n * sum: 节点及其子树的和/n * lazy: 懒惰标记,用来标记该节点是否进行了翻转操作/n * size: 节点的大小,即节点及其子树的节点个数/n * fa: 父节点指针/n * ch[2]: 左右孩子指针/n/n2. 基本操作:/n * getSize(Node *x): 获取节点的大小/n * update(Node *x): 更新节点的信息/n * reverse(Node *x): 修改节点的懒惰标记/n * pushdown(Node *x): 下传懒惰标记/n * getDir(Node *x): 判断节点是否为其父节点的左孩子/n/n3. Splay Tree 操作:/n * rotate(Node *x): 旋转操作/n * splay(Node *x): 伸展操作/n * access(Node *x): 获取根节点/n * makeRoot(Node *x): 将x节点设置为根节点/n/n4. LCT 操作:/n * link(Node *x, Node *y): 将x节点和y节点连接/n * cut(Node *x, Node *y): 将x节点和y节点断开/n * query(Node *x): 查询x节点所在的树的和/n * updateValue(Node *x, int v): 修改x节点的值/n/n### 4. 应用举例/n/nA+B Problem:/n/n对于 A+B 问题,只需要将两个节点连接起来,然后查询这两个节点所在的树的和即可。/n/ncpp/nint main() {/n int a, b;/n cin >> a >> b;/n // 创建两个节点/n Node *node1 = new Node();/n Node *node2 = new Node();/n // 设置节点的值/n node1->val = a;/n node2->val = b;/n // 连接两个节点/n link(node1, node2);/n // 查询两个节点所在的树的和/n cout << query(node1) << endl;/n return 0;/n}/n/n/n## 总结/n/nLCT 算法是一种非常强大的动态树维护算法,它可以解决很多复杂的树形问题。在学习 LCT 的过程中,需要熟练掌握 Splay Tree 的基本操作,以及 LCT 算法的各种操作和应用。/n/n希望本篇文章能帮助你更好地理解 LCT 算法,并应用它来解决实际问题。

C++ LCT 算法详解:A+B Problem

原文地址: https://www.cveoy.top/t/topic/pkn2 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录