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

算法笔记-线段树合并

线段树合并

前置知识:权值线段树、动态开点

将两棵线段树的信息合并成一棵线段树。
可以新建一颗线段树保存原来两颗线段树的信息,也可以将第二棵线段树维护的信息加到第一棵线段树上。

前者的空间复杂度较高,如果合并之前的线段树不会再用到的话,可以将第二颗线段树的信息加到第一棵线段树上。

P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

题意:

一棵树有 n n n 个点。每次操作 ( x , y , z ) (x,y,z) (x,y,z) 在路径 ( x , y ) (x,y) (x,y) 上的每一个点放一个救济粮 z z z。询问每个点存放最多的是哪种救济粮

解析:

对于树上一条路径上的点进行相同的操作,可以想到树上差分。

然后统计每个点最多的东西,可以用权值线段树维护每种救济粮的数目。

因为将发放救济粮转化成树上差分,求答案的时候需要合并,所以从下向上合并线段树。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 1e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;int head[maxn], tot;
struct edge{int to, nxt;
}e[maxn << 1];
struct node{int mcnt, id;int ls, rs;
}t[maxn * 60];
struct query{int x, y, z;
}q[maxn];int cnt;
int n, m, MAX;
int rt[maxn], ans[maxn];
void add(int a, int b){e[++tot].nxt = head[a];e[tot].to = b;head[a] = tot;
}
int dep[maxn], siz[maxn], top[maxn], son[maxn], fa[maxn];
void dfs1(int u, int p){dep[u] = dep[p] + 1;siz[u] = 1;fa[u] = p;for(int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if(v == p)continue;dfs1(v, u);siz[u] += siz[v];if(siz[v] > siz[son[u]])son[u] = v;}
}
void dfs2(int u, int tp){top[u] = tp;if(son[u])dfs2(son[u], tp);for(int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if(v == fa[u] || v == son[u])continue;dfs2(v, v);}
}
int LCA(int u, int v){while(top[u] != top[v]){if(dep[top[u]] < dep[top[v]])swap(u, v);u = fa[top[u]];}return dep[u] < dep[v] ? u : v;
}
void pushup(int k){if(t[t[k].ls].mcnt >= t[t[k].rs].mcnt){t[k].mcnt = t[t[k].ls].mcnt;t[k].id = t[t[k].ls].id;}else{t[k].mcnt = t[t[k].rs].mcnt;t[k].id = t[t[k].rs].id;}
}
void update(int &k, int l, int r, int pos, int v){if(k == 0)k = ++cnt;if(l == r && l == pos){t[k].mcnt += v;t[k].id = l;return;}int mid = (l+r) >> 1;if(pos <= mid)update(t[k].ls, l, mid, pos, v);elseupdate(t[k].rs, mid+1, r, pos, v);pushup(k);
}
void merge(int &a, int b, int l, int r){if(!a || !b){a = (!a ? b : a);return;}	if(l == r){t[a].mcnt += t[b].mcnt;t[a].id = l;return;}int mid = (l+r) >> 1;merge(t[a].ls, t[b].ls, l, mid);merge(t[a].rs, t[b].rs, mid+1, r);pushup(a);
}
void dfs(int u){for(int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if(v == fa[u])continue;dfs(v);merge(rt[u], rt[v], 1, MAX);}if(t[rt[u]].mcnt != 0)ans[u] = t[rt[u]].id;
}
int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> m;for(int i = 1, u, v; i < n; i++){cin >> u >> v;add(u, v);add(v, u);}dfs1(1, 0);dfs2(1, 1);for(int i = 1; i <= m; i++){cin >> q[i].x >> q[i].y >> q[i].z;MAX = max(MAX, q[i].z);}for(int i = 1; i <= m; i++){int u = q[i].x, v = q[i].y;int w = q[i].z;int lca = LCA(u, v);update(rt[u], 1, MAX, w, 1);update(rt[v], 1, MAX, w, 1);update(rt[lca], 1, MAX, w, -1);if(fa[lca])update(rt[fa[lca]], 1, MAX, w, -1);}dfs(1);for(int i = 1; i <= n; i++)cout << ans[i] << endl;return 0;
}


P1600 [NOIP2016 提高组] 天天爱跑步

题意:

一棵 n n n 节点的树,有 m m m 条路径,每个节点有参数 w i w_i wi。询问有多少条路径的第 w i + 1 w_i+1 wi+1 个点是节点 i i i

解析:

对于每条路径 ( s , t ) (s, t) (s,t),可以分成两条路径 ( s , l c a ) (s,lca) (s,lca) ( l c a , t ) (lca,t) (lca,t),如果模拟这个过程的话,时间复杂度为 O ( n m ) O(nm) O(nm) 不能接受。

换个角度考虑,对于每个点,有多少条路径会对该点产生贡献。

设节点 i i i 的深度为 d e p i dep_i depi

设路径 ( s , t ) (s,t) (s,t) 对节点 u u u 产生贡献。

  • u u u ( s , l c a ) (s,lca) (s,lca) 上。 d e p s − d e p u = w u dep_s-dep_u = w_u depsdepu=wu
  • u u u ( l c a , t ) (lca, t) (lca,t) 上。 d e p s + d e p u − 2 d e p l c a = w u dep_s+dep_u-2dep_{lca} = w_u deps+depu2deplca=wu

即满足条件的路径会对节点 u u u 有贡献。

考虑树上差分,在 s s s 插入 d e p s dep_s deps,在 t t t 处插入 2 d e p l c a − d e p s 2dep_{lca}-dep_s 2deplcadeps,在 l c a lca lca 处插入 − d e p s -dep_s deps,在 f a ( l c a ) fa(lca) fa(lca) 处插入 d e p s − 2 d e p l c a dep_s-2dep_{lca} deps2deplca。后两者可以交换,然后线段树合并即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 3e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;int head[maxn], cnt;
struct edge{int to, nxt;
}e[maxn << 1];
struct node{int v;int ls, rs;
}t[maxn * 60];
int n, m;
int rt[maxn], MAX, ans[maxn], w[maxn], tot;
void add(int a, int b){e[++cnt].nxt = head[a];e[cnt].to = b;head[a] = cnt;
} 
int siz[maxn], son[maxn], dep[maxn], fa[maxn], top[maxn];
void dfs1(int u, int p){dep[u] = dep[p]+1;siz[u] = 1;fa[u] = p;for(int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if(v == p)continue;dfs1(v, u);siz[u] += siz[v]; if(siz[v] > siz[son[u]])son[u] = v;}
}
void dfs2(int u, int tp){top[u] = tp;if(son[u])dfs2(son[u], tp);for(int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if(v == son[u] || v == fa[u])continue;dfs2(v, v);}
}
int LCA(int u, int v){while(top[u] != top[v]){if(dep[top[u]] < dep[top[v]])swap(u, v);u = fa[top[u]];}return dep[u] < dep[v] ? u : v;
}
void update(int &k, int l, int r, int pos, int v){if(k == 0)k = ++tot;if(l == r && l == pos){t[k].v += v;return;}int mid = (l+r) >> 1;if(pos <= mid)update(t[k].ls, l, mid, pos, v);elseupdate(t[k].rs, mid+1, r, pos, v);return;
}
void merge(int &a, int b, int l, int r){if(!a || !b){a = (!a ? b : a);return;}if(l == r){t[a].v += t[b].v;return;}int mid = (l+r) >> 1;merge(t[a].ls, t[b].ls, l, mid);merge(t[a].rs, t[b].rs, mid+1, r);
}
int query(int k, int l, int r, int pos){if(!k)return 0;if(l == r)return t[k].v;int mid = (l+r) >> 1;if(pos <= mid)return query(t[k].ls, l, mid, pos);elsereturn query(t[k].rs, mid+1, r, pos);
}
void dfs(int u){for(int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if(v == fa[u])continue;dfs(v);merge(rt[u], rt[v], 1, MAX);}if(w[u] && n + dep[u] + w[u] <= MAX)ans[u] += query(rt[u], 1, MAX, n + dep[u] + w[u]);ans[u] += query(rt[u], 1, MAX, n + dep[u] - w[u]);}int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> m;MAX = n << 1;int u, v;for(int i = 1; i < n; i++){cin >> u >> v;add(u, v);add(v, u);}dfs1(1, 0);dfs2(1, 1);for(int i = 1; i <= n; i++)cin >> w[i];for(int i = 1; i <= m; i++){cin >> u >> v;int lca = LCA(u, v);update(rt[u], 1, MAX, n + dep[u], 1);update(rt[v], 1, MAX, n + dep[lca] * 2 - dep[u], 1);update(rt[lca], 1, MAX, n + dep[u], -1);update(rt[fa[lca]], 1, MAX, n + dep[lca] * 2 - dep[u], -1);}dfs(1);for(int i = 1; i <= n; i++)cout << ans[i] << " ";cout << endl;return 0;
}


P3224 [HNOI2012]永无乡

题意:

n n n 个节点,每个节点有互不相同的重要程度。两种操作:

  • ( x , y ) (x,y) (x,y) 之间建桥
  • 询问与节点 x x x 所在连通块中重要程度排名第 k k k 小的节点编号

解析:

查询第 k k k 小,考虑权值线段树;维护联通性,考虑并查集。在合并两个连通块时,也合并权值线段树

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 3e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;struct node{int sum, id;int ls, rs;
}t[maxn * 60];
int rt[maxn];
int tot, n, m, q;
int fa[maxn];
int find(int x){return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int pushup(int k){t[k].sum = t[t[k].ls].sum + t[t[k].rs].sum;
}
void update(int &k, int l, int r, int pos, int idx){if(k == 0)k = ++tot;if(l == r){t[k].sum++;t[k].id = idx;return;}int mid = (l+r) >> 1;if(pos <= mid)update(t[k].ls, l, mid, pos, idx);elseupdate(t[k].rs, mid+1, r, pos, idx);pushup(k);
}
void merge(int &a, int b, int l, int r){if(!a || !b){a = (a == 0 ? b : a);return;}if(l == r){t[a].sum += t[b].sum;return;}int mid = (l+r) >> 1;merge(t[a].ls, t[b].ls, l, mid);merge(t[a].rs, t[b].rs, mid+1, r);pushup(a);
}
int query(int a, int k, int l, int r){if(t[a].sum < k || !a)return 0;if(l == r)return t[a].id;int mid = (l+r) >> 1;int ans = 0;if(k <= t[t[a].ls].sum)ans = query(t[a].ls, k, l, mid);elseans = query(t[a].rs, k-t[t[a].ls].sum, mid+1, r);return ans;
}
int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> m;for(int i = 1, p; i <= n; i++){fa[i] = i;cin >> p;update(rt[i], 1, n, p, i);}for(int i = 1, x, y; i <= m; i++){cin >> x >> y;int fx = find(x);int fy = find(y);fa[fy] = fx;merge(rt[fx], rt[fy], 1, n);}cin >> q;string op;for(int i = 1, x, y; i <= q; i++){cin >> op >> x >> y;if(op == "B"){int fx = find(x);int fy = find(y);if(fx == fy)continue;fa[fy] = fx;merge(rt[fx], rt[fy], 1, n); }else if(op == "Q"){int fx = find(x);int res = query(rt[fx], y, 1, n);if(res == 0)cout << -1 << endl;elsecout << res << endl;}}	return 0;
}

相关文章:

算法笔记-线段树合并

线段树合并 前置知识&#xff1a;权值线段树、动态开点 将两棵线段树的信息合并成一棵线段树。 可以新建一颗线段树保存原来两颗线段树的信息&#xff0c;也可以将第二棵线段树维护的信息加到第一棵线段树上。 前者的空间复杂度较高&#xff0c;如果合并之前的线段树不会再用…...

Fiddler抓取IOS数据包实践教程

Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(指cookie,html,js,css等文件)。 本章教程,主要介绍如何利用Fiddler抓取IOS数据包相关教程。 目录 一、打开Fiddler监听端口 二、配置网…...

Ansible基础4——变量、机密、事实

文章目录 一、变量二、机密2.1 创建加密文件2.2 查看加密文件2.3 编辑加密文件内容2.4 加密现有文件2.5 解密文件2.6 更改加密密码 三、事实3.1 收集展示事实3.2 展示某个结果3.3 新旧事实命令3.4 关闭事实3.5 魔法变量 一、变量 常设置的变量&#xff1a; 要创建的用户要安装的…...

React实现Vue的watch监听属性

在 Vue 中可以简单地使用 watch 来监听数据的变化&#xff0c;还能获取到改变前的旧值&#xff0c;而在 React 中是没有 watch 的。 React中比较复杂&#xff0c;但是我们如果想在 React 中实现一个类似 Vue 的 watch 监听属性&#xff0c;也不是没有办法。 在React类组件中实…...

axios、跨域与JSONP、防抖和节流

文章目录 一、axios1、什么是axios2、axios发起GET请求3、axios发起POST请求4、直接使用axios发起请求 二、跨域与JSONP1、了解同源策略和跨域2、JSONP&#xff08;1&#xff09;实现一个简单的JSONP&#xff08;2&#xff09;JSONP的缺点&#xff08;3&#xff09;jQuery中的J…...

macOS Ventura 13.5beta2 (22G5038d)发布

系统介绍 黑果魏叔 6 月 1 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 2 更新&#xff08;内部版本号&#xff1a;22G5038d&#xff09;&#xff0c;本次更新距离上次发布隔了 12 天。 macOS Ventura 带来了台前调度、连续互通相机、Fac…...

jwt----介绍,原理

token&#xff1a;服务的生成的加密字符串&#xff0c;如果存在客户端浏览器上&#xff0c;就叫cookie -三部分&#xff1a;头&#xff0c;荷载&#xff0c;签名 -签发&#xff1a;登录成功&#xff0c;签发 -认证&#xff1a;认证类中认证 # jwt&…...

Three.js--》实现3d水晶小熊模型搭建

目录 项目搭建 初始化three.js基础代码 加载背景纹理 加载小熊模型 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 项目搭建 本案例还是借助框架书写…...

《阿里大数据之路》研读笔记(1)

首先先看到OLAP和OLTP的区别&#xff1a; OLTP(Online transaction processing):在线/联机事务处理。典型的OLTP类操作都比较简单&#xff0c;主要是对数据库中的数据进行增删改查&#xff0c;操作主体一般是产品的用户或者是操作人员。 OLAP(Online analytical processing):…...

Logback 日志框架详解

一、Logback 简介 Logback 是一个日志框架&#xff0c;旨在成为 log4j 的替代品。它由 Ceki Glc 创建并维护&#xff0c;是一款开源的日志框架&#xff0c;是 slf4j&#xff08;Simple Logging Facade for Java&#xff09;的实现。相比于 log4j&#xff0c;Logback 具有更高的…...

BIO、NIO、AIO 有什么区别?

BIO (Blocking I/O)&#xff1a; Block IO 同步阻塞式 IO &#xff0c;传统 IO&#xff0c;特点是模式简单、使用方便&#xff0c;并发处理能力低。 同步阻塞 I/O 模式&#xff0c;数据的读取写入必须阻塞在一个线程内等待其完成&#xff0c;在活动连接数不是特别高&#xff08…...

nginx和tomcat负载均衡、静态分离

tomcat重要目录 bin 存放启动和关闭Tomcat脚本conf存放Tomcat不同的配置文件doc存放Tomcat文档lib存放Tomcat运行需要的库文件logs存放Tomcat执行时的log文件src存放Tomcat的源代码webappsTomcat的主要Web发布目录work存放jsp编译后产生的class文件 nginx负载均衡原理 nginx实…...

用AI写出的高考作文!

今天是6月7日&#xff0c;又到了每一年高考的日子。小灰自己参加高考是在2004年&#xff0c;距离现在已经将近20年&#xff0c;现在回想起来&#xff0c;真的是恍如隔世。 今天高考语文的作文题是什么呢&#xff1f; 全国甲卷的题目是&#xff1a;人技术时间 人们因技术发展得以…...

chatgpt赋能python:Python屏幕输入介绍:了解命令行输入的基本知识

Python屏幕输入介绍&#xff1a;了解命令行输入的基本知识 Python是一种使用广泛的编程语言&#xff0c;用于编写各种类型的应用程序&#xff0c;包括图形用户界面应用程序和基于命令行的应用程序。对于基于命令行的应用程序来说&#xff0c;屏幕输入非常重要。本文将介绍Pyth…...

bert中文文本摘要代码(1)

bert中文文本摘要代码 写在最前面关于BERT使用transformers库进行微调 load_data.py自定义参数collate_fn函数BertDataset类主函数 tokenizer.py创建词汇表encode函数decode函数 写在最前面 熟悉bert&#xff0b;文本摘要的下游任务微调的代码&#xff0c;方便后续增加组件实现…...

为何溃坝事故频发,大坝安全如何保障?

随着水利水电工程的重要性日益突显&#xff0c;水库大坝安全越来越受到相关部门的重视。因为大坝的安全直接影响水利工程的功能与作用&#xff0c;因此对大坝安全的监测显得十分必要。大坝安全监测的作用是能够及时掌握大坝的运行状态&#xff0c;及时发现大坝的变形、渗漏等异…...

第十九章_手写Redis分布式锁

锁的种类 单机版同一个JVM虚拟机内synchronized或者Lock接口。 分布式多个不同JVM虚拟机&#xff0c;单机的线程锁机制不再起作用&#xff0c;资源类在不同的服务器之间共享了。 一个靠谱分布式锁需要具备的条件和刚需 独占性 &#xff1a;OnlyOne&#xff0c;任何时刻只能有且…...

电路设计【8】原理图中VCC、VDD、VEE、VSS、VBAT各表示什么意思

文章目录 一、名词解析二、应用讲解三、举例分析&#xff1a;为什么stm32vet6中要分出5对VDD VSS&#xff1f;它们分别负责哪些模块的供电&#xff1f; 一、名词解析 &#xff08;1&#xff09;VCC&#xff1a;Ccircuit 表示电路的意思, 即接入电路的电压 &#xff08;2&…...

Volatile、Synchronized、ReentrantLock锁机制使用说明

一、Volatile底层原理 volatile是轻量级的同步机制&#xff0c;volatile保证变量对所有线程的可见性&#xff0c;不保证原子性。 当对volatile变量进行写操作的时候&#xff0c;JVM会向处理器发送一条LOCK前缀的指令&#xff0c;将该变量所在缓存行的数据写回系统内存。由于缓…...

港联证券|AI概念股继续活跃 科创50指数逆势走高

周三&#xff0c;A股市场出现极致分化态势。得益于存储芯片为代表的硬科技股的强势&#xff0c;科创50指数逆势走高。但创业板指、深证成指等主要股指仍然跌跌不休&#xff0c;沪指险守3200点关口。AI概念股继续逆势活跃&#xff0c;国资云、数据方向领涨&#xff0c;算力概念股…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...