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

第三章 图论 No.8最近公共祖先lca, tarjan与次小生成树

文章目录

    • lca
    • Tarjan
      • 板子题:1172. 祖孙询问
      • lca或tarjan:1171. 距离
      • 356. 次小生成树
      • 352. 闇の連鎖

image.png

lca

O ( m l o g n ) O(mlogn) O(mlogn),n为节点数量,m为询问次数,lca是一种在线处理询问的算法
自己也是自己的祖先

倍增:
f a ( i , j ) fa(i, j) fa(i,j)表示从i开始,向上走 2 j 2^j 2j步走到的点
j = 0,走到父节点
j > 0,分两步走,先走到 2 j − 1 2^{j-1} 2j1步再走 2 j − 1 2^{j-1} 2j1步,那么一共就会走 2 j 2^j 2j步, f a ( i , j ) = f a ( f a ( i , j − 1 ) , j − 1 ) fa(i, j) = fa(fa(i, j-1), j-1) fa(i,j)=fa(fa(i,j1),j1)
d e p t h ( i ) depth(i) depth(i)表示层数

  1. 将两点跳到同一层
  2. 让两个点同时往上跳,直到跳到公共祖先的下一层

第一步:基于二进制的思想,x和y之间的层数差距为 d e p t h ( x ) − d e p t h ( y ) depth(x) - depth(y) depth(x)depth(y),假设y的层数小于x的层数,此时x要往上跳
若要跳k层,那么根据k的二进制表示将k拆分成多个2的幂相加,由于我们已经预处理了 f ( i , j ) f(i, j) f(i,j),所以根据 f ( i , j ) f(i, j) f(i,j)的值往上跳即可
f ( x , k ) = f ( y , k ) f(x, k) = f(y, k) f(x,k)=f(y,k)时,即x往上跳k步和y往上跳k步后,位于同一个位置,此时找到了一个公共祖先,但不是最近公共祖先,所以这里要减小k的值,直到 f ( x , k ) ≠ f ( y , k ) f(x, k) ≠ f(y, k) f(x,k)=f(y,k),此时才找到了最近公共祖先

规定 d e p t h ( 0 ) = 0 depth(0) = 0 depth(0)=0,0号点为哨兵,位于第0层,根节点位于第一层
向上跳 2 k 2^k 2k步后,若跳出了这颗树,那么 f ( i , k ) = 0 f(i, k) = 0 f(i,k)=0

image.png

预处理depth和fa的板子:

void bfs(int root)
{memset(dis, 0x3f, sizeof(dis));q[tt ++ ] = root;depth[root] = 1, depth[0] = 0;while (tt >= hh){int x = q[hh ++ ];for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (depth[y] > depth[x] + 1){depth[y] = depth[x] + 1;q[tt ++ ] = y;fa[y][0] = x;for (int k = 1; k <= c; ++ k )fa[y][k] = fa[fa[y][k - 1]][k - 1];}}}
}

lca板子:

int lca(int x, int y)
{if (depth[x] < depth[y]) swap(x, y);for (int k = c; k >= 0; -- k )if (depth[fa[x][k]] >= depth[y])x = fa[x][k];if (x == y) return y;for (int k = c; k >= 0; -- k )if (fa[x][k] != fa[y][k]){x = fa[x][k];y = fa[x][k];}return fa[x][0];
}

Tarjan

O ( n + m ) O(n + m) O(n+m) ,n为节点数量,m为询问次数
tarjan是一种离线处理询问的算法,是向上标记法的优化
在深度优先遍历时,将所有点分成三大类

  1. 已经遍历过且已经回溯的点
  2. 已经遍历但正在搜索的分支
  3. 还未搜索到的点

image.png
将已经遍历且回溯的点标记成2,正在遍历的点标记成1,未遍历的点标记成0
对于正在回溯的点,需要处理所有有关该点的询问信息:若询问的另外一个点已经遍历过(回溯完成),那么该点将被分到一个集合中,集合的代表点就是两点的最近公共祖先
比如上图,当前正在遍历x这个点,已经遍历完的点为绿色部分,这些点所属集合的代表点位于红色分支上

模板:

// 用dfs维护dis数组
void dfs(int x, int fa)
{for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (y != fa){dis[y] = dis[x] + w[i];dfs(y, x);}}
}// tarjan处理询问
void tarjan(int x)
{st[x] = 1; // 当前正在遍历该点for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (!st[y]) // 当前为遍历ydian{tarjan(y);p[y] = u;}}for (auto item : query[x]) // 处理有关当前节点的询问{int y = item.first, id = item.first; // id为该询问的唯一编号if (st[y] == 2) // 询问的另一点已经遍历过{int anc = find(y); // 找到集合的代表点,公共祖先res[id] = dis[x] + dis[y] - 2 * dis[anc]; // 根据id将答案存储到数组中}}st[x] = 2; // 当前节点遍历完
}

板子题:1172. 祖孙询问

1172. 祖孙询问 - AcWing题库
image.png

由于树的层数最大有40000层,所以一个节点最多向上跳 l o g 400000 log400000 log400000层,大概是一个大于 2 15 2^{15} 215小于 2 16 2^{16} 216的数,所以最多跳 2 16 − 1 2^{16} - 1 2161层,二进制位取15即可

#include <iostream>
#include <cstring>
using namespace std;const int N = 4e4 + 10, M = 2 * N;
int h[N], e[M], ne[M], idx;
int q[N], hh, tt = -1;
int depth[N], fa[N][16]; // 最多跳2^16-1
int n;void add(int x, int y)
{e[idx] = y, ne[idx] = h[x], h[x] = idx ++ ;
}void bfs(int root)
{q[++ tt] = root;memset(depth, 0x3f, sizeof(depth));depth[0] = 0, depth[root] = 1;while (tt >= hh){int x = q[hh ++ ];for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (depth[y] > depth[x] + 1){depth[y] = depth[x] + 1;fa[y][0] = x;q[++ tt ] = y;for (int k = 1; k <= 15; ++ k )fa[y][k] = fa[fa[y][k - 1]][k - 1];}}}
}int lca(int x, int y)
{if (depth[x] < depth[y]) swap(x, y);for (int k = 15; k >= 0; -- k )if (depth[fa[x][k]] >= depth[y])x = fa[x][k];if (x == y) return y;for (int k = 15; k >= 0; -- k )if (fa[x][k] != fa[y][k]){x = fa[x][k];y = fa[y][k];}return fa[x][0];
}int main()
{memset(h, -1, sizeof(h));scanf("%d", &n);int root;int a, b;for (int i = 0; i < n; ++ i ){scanf("%d%d", &a, &b);if (b == -1) root = a;else add(a, b), add(b, a);}bfs(root);int m;scanf("%d", &m);for (int i = 0; i < m; ++ i ){scanf("%d%d", &a, &b);int t = lca(a, b);if (t == a) puts("1");else if (t == b) puts("2");else puts("0");}return 0;
}

lca或tarjan:1171. 距离

1171. 距离 - AcWing题库
image.png

与上题一样,题目要处理很多询问,可以用lca或者离线tarjan解决
树的最短路问题可以从公共祖先的角度考虑,假设x和y的公共祖先为t, d i s ( t ) dis(t) dis(t)为根节点到t的距离,那么x和y之间的最短距离就是 d i s ( x ) + d i s ( y ) − 2 ∗ d i s ( t ) dis(x) + dis(y) - 2 * dis(t) dis(x)+dis(y)2dis(t)

题目没有给定根节点,我们任意指定一个点为根节点即可

lca解法:

#include <iostream>
#include <cstring>
using namespace std;const int N = 1e4 + 10, M = 2 * N;
int h[N], e[M], ne[M], w[M], idx;
int depth[N], fa[N][16];
int q[N], hh, tt = -1;
int dis[N];void add(int x, int y, int d)
{e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}void dfs(int root)
{memset(depth, 0x3f, sizeof(depth));depth[0] = 0, depth[root] = 1;q[++ tt ] = root;while (tt >= hh){int x = q[hh ++ ];for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (depth[y] > depth[x] + 1){depth[y] = depth[x] + 1;dis[y] = dis[x] + w[i];fa[y][0] = x;q[++ tt ] = y;for (int k = 1; k <= 15; ++ k )fa[y][k] = fa[fa[y][k - 1]][k - 1];}}}
}int lca(int x, int y)
{if (depth[x] < depth[y]) swap(x, y);for (int k = 15; k >= 0; -- k )if (depth[fa[x][k]] >= depth[y])x = fa[x][k];if (x == y) return y;for (int k = 15; k >= 0; -- k )if (fa[x][k] != fa[y][k]){x = fa[x][k];y = fa[y][k];}return fa[x][0];
}int main()
{memset(h, -1, sizeof(h));int n, m;scanf("%d%d", &n, &m);int x, y, d;for (int i = 0; i < n - 1; ++ i ){scanf("%d%d%d", &x, &y, &d);add(x, y, d), add(y, x, d);}dfs(1);for (int i = 0; i < m; ++ i ){scanf("%d%d", &x, &y);int t = lca(x, y);printf("%d\n", dis[x] + dis[y] - 2 * dis[t]);}return 0;
}

tarjan解法:

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;const int N = 1e4 + 10, M = 2 * N;
typedef pair<int, int> PII;
vector<PII> query[N];
int h[N], e[M], ne[M], w[M], idx;
int res[M], dis[N], st[N], p[N];
int n, m;void add(int x, int y, int d)
{e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}void dfs(int x, int fa)
{for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (y != fa){dis[y] = dis[x] + w[i];dfs(y, x);}}
}int find(int x)
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}void tarjan(int x)
{st[x] = 1;for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (!st[y]){tarjan(y);p[y] = x;}}for (auto item : query[x]){int y = item.first, id = item.second;if (st[y] == 2){int anc = find(y);res[id] = dis[x] + dis[y] - 2 * dis[anc];}}st[x] = 2;
}int main()
{memset(h, -1, sizeof(h));scanf("%d%d", &n, &m);int x, y, d;for (int i = 0; i < n - 1; ++ i ){scanf("%d%d%d", &x, &y, &d);add(x, y, d), add(y, x, d);}for (int i = 0; i < m; ++ i ){scanf("%d%d", &x, &y);query[x].push_back({y, i}); // 将查询的另一个点与查询编号保存query[y].push_back({x, i});}dfs(1, -1);for (int i = 1; i <= n; ++ i ) p[i] = i;tarjan(1);for (int i = 0; i < m; ++ i ) printf("%d\n", res[i]);return 0;
}

debug:维护的query信息要不同地插入两次

query[x].push_back({y, i});
query[y].push_back({x, i});

因为当前询问有关x的信息时,y可能没有遍历完,但是询问y有关的信息时,x是遍历完的


356. 次小生成树

356. 次小生成树 - AcWing题库
image.png

d 1 ( i , j ) d1(i, j) d1(i,j)表示从i往上跳 2 j 2^j 2j层后,路径上的最大边权
d 2 ( i , j ) d2(i, j) d2(i,j)表示从i往上跳 2 j 2^j 2j层后,路径上的次大边权
2 j 2^j 2j步是一个类似分治的过程,分成两部分跳,这两部分依旧能分成两部分跳
路径上的最大值为每一段的最大值取max,次大值为所有子路径的最大值和次大值中的第二大,每次遍历子线段时维护信息即可

if (d > d1) d2 = d1, d1 = d; 
else if (d != d1 && d > d2) d2 = d;
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;typedef long long LL;
const int N = 1e5 + 10, M = 3e5 + 10, INF = 0x3f3f3f3f;
struct Edge
{int x, y, w;bool f;bool operator<(const Edge& e) const {return w < e.w;}
}edges[M];int h[N], e[M], ne[M], w[M], idx;
int p[N], depth[N], fa[N][17];
int q[N], hh, tt = -1;
int d1[N][17], d2[N][17];
int d[M];
int n, m;void add(int x, int y, int d)
{e[idx] = y, ne[idx] = h[x], w[idx] = d, h[x] = idx ++ ;
}int find(int x)
{if (x != p[x]) p[x] = find(p[x]);return p[x];
}LL kruskal()
{LL res = 0;sort(edges, edges + m);for (int i = 1; i <= n; ++ i ) p[i] = i;for (int i = 0; i < m; ++ i ){auto t = edges[i];int x = t.x, y = t.y, w = t.w;int px = find(x), py = find(y);if (px != py){res += w;p[px] = py;edges[i].f = true;add(x, y, w), add(y, x, w);}}return res;
}void bfs()
{q[++ tt ] = 1;memset(depth, 0x3f, sizeof(depth));depth[0] = 0, depth[1] = 1;while (tt >= hh){int x = q[hh ++ ];for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (depth[y] > depth[x] + 1){depth[y] = depth[x] + 1;fa[y][0] = x;d1[y][0] = w[i], d2[y][0] = -INF;q[++ tt ] = y;for (int k = 1; k <= 16; ++ k ){int mid = fa[y][k - 1];fa[y][k] = fa[mid][k - 1];d1[y][k] = d2[y][k] = -INF;int a[4] = { d1[mid][k - 1], d2[mid][k - 1], d1[y][k - 1], d2[y][k - 1] };for (int i = 0; i < 4; ++ i ){if (a[i] > d1[y][k]) d2[y][k] = d1[y][k], d1[y][k] = a[i];else if (a[i] != d1[y][k] && a[i] > d2[y][k]) d2[y][k] = a[i];}}}}}
}int lca(int x, int y, int w)
{int cnt = 0;if (depth[x] < depth[y]) swap(x, y);for (int k = 16; k >= 0; -- k )if (depth[fa[x][k]] >= depth[y]){d[cnt ++ ] = d1[x][k];d[cnt ++ ] = d2[x][k];x = fa[x][k];}if (x != y){for (int k = 16; k >= 0; -- k ){if (fa[x][k] != fa[y][k]){d[cnt ++ ] = d1[x][k], d[cnt ++ ] = d2[x][k];d[cnt ++ ] = d1[y][k], d[cnt ++ ] = d2[y][k];x = fa[x][k], y = fa[y][k];}d[cnt ++ ] = d1[x][0], d[cnt ++ ] = d2[x][0];d[cnt ++ ] = d1[y][0], d[cnt ++ ] = d2[y][0];}}int dmax1 = -INF, dmax2 = -INF;for (int i = 0; i < cnt; ++ i ){if (d[i] > dmax1) dmax2 = dmax1, dmax1 = d[i];else if (d[i] != dmax1 && d[i] > dmax2) dmax2 = d[i];}if (w > dmax1) return w - dmax1;return w - dmax2;
}int main()
{memset(h, -1, sizeof(h));scanf("%d%d", &n, &m);for (int i = 0; i < m; ++ i )scanf("%d%d%d", &edges[i].x, &edges[i].y, &edges[i].w);LL sum = kruskal(); // 最小生成树的权值bfs();LL res = 1e19;for (int i = 0; i < m; ++ i )if (!edges[i].f)res = min(res, sum + lca(edges[i].x, edges[i].y, edges[i].w));printf("%lld\n", res);return 0;
}

352. 闇の連鎖

352. 闇の連鎖 - AcWing题库
image.png

image.png

树上差分,将x到y的最短路径上所有的边加上c,若p为x和y的公共祖先,那么
d(x) += c, d(y) += c, d(p) -= 2c
如何计算某条边的权值?以这条边的子节点为根的子树中,所有边的权值相加为这条边的权值

在一颗树中,删除任意一条边,那么这颗树将被切成两个连通块
若向树中再添加一条边,那么这条非树边和树边就一定构成环,要向将此时的“树”切成两个连通块,就要删除环中的任意一条树边与这条非树边
题目限制只能先切树边,再切非树边,一共两次,两次过后还没有切成两个连通块,说明这个方案行不通
当切除树边,不用再切除非树边就得到两个连通块时,由于题目限制,还需要切除一条非树边,假设非树边有m条,那么此时可以选择m条边中的任意一条切除,此时的方案数为m
若切除树边后,还要再切除一条非树边,才能得到两个连通块时,此时的方案数为1,只能切除这条环中的非树边
若切除树边后,还要再切除大于一条的非树边,此时无法再切除,方案数为0

现在的问题是,如何知道切除某条树边后,还需要再切除几条非树边?
假设现在已经用树边建立了一棵树,此时再添加非树边将构成环,将环中的所有树边权值加1,假设初始权值为0,此时可以使用树上差分
然后遍历所有的树边,根据边权计算方案数

#include <iostream>
#include <cstring>
using namespace std;const int N = 1e5 + 10, M = 2e5 + 10;
int h[N], e[M], ne[M], idx;
int depth[N], fa[N][17];
int q[N], hh, tt = -1;
int d[N];
int n, m, ans;void add(int x ,int y)
{e[idx] = y, ne[idx] = h[x], h[x] = idx ++ ;
}void bfs()
{memset(depth, 0x3f, sizeof(depth));depth[0] = 0, depth[1] = 1;q[++ tt ] = 1;while (tt >= hh){int x = q[hh ++ ];for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (depth[y] > depth[x] + 1){depth[y] = depth[x] + 1;fa[y][0] = x;q[++ tt ] = y;for (int k = 1; k <= 16; ++ k )fa[y][k] = fa[fa[y][k - 1]][k - 1];}}}
}int lca(int x, int y)
{if (depth[x] < depth[y]) swap(x, y);for (int k = 16; k >= 0; -- k )if (depth[fa[x][k]] >= depth[y])x = fa[x][k];if (x == y) return x;for (int k = 16; k >= 0; -- k )if (fa[x][k] != fa[y][k]){x = fa[x][k];y = fa[y][k];}return fa[x][0];
}int dfs(int x, int f)
{int res = d[x];for (int i = h[x]; i != -1; i = ne[i]){int y = e[i];if (f != y){int t = dfs(y, x);if (t == 0) ans += m;else if (t == 1) ans ++;res += t;}}return res;
}int main()
{memset(h, -1, sizeof(h));scanf("%d%d", &n, &m);int x, y;for (int i = 0; i < n - 1; ++ i ){        scanf("%d%d", &x, &y);add(x, y), add(y, x);}bfs();int res = 0;for (int i = 0; i < m; ++ i){scanf("%d%d", &x, &y);int p = lca(x, y);d[x] ++, d[y] ++, d[p] -= 2;}dfs(1, -1);printf("%d\n", ans);return 0;
}

相关文章:

第三章 图论 No.8最近公共祖先lca, tarjan与次小生成树

文章目录 lcaTarjan板子题&#xff1a;1172. 祖孙询问lca或tarjan&#xff1a;1171. 距离356. 次小生成树352. 闇の連鎖 lca O ( m l o g n ) O(mlogn) O(mlogn)&#xff0c;n为节点数量&#xff0c;m为询问次数&#xff0c;lca是一种在线处理询问的算法 自己也是自己的祖先 倍…...

[Kubernetes]Kubeflow Pipelines - 基本介绍与安装方法

1. 背景 近些年来&#xff0c;人工智能技术在自然语言处理、视觉图像和自动驾驶方面都取得不小的成就&#xff0c;无论是工业界还是学术界大家都在惊叹一个又一个的模型设计。但是对于真正做过算法工程落地的同学&#xff0c;在惊叹这些模型的同时&#xff0c;更多的是在忧虑如…...

Sui网络的稳定性和高性能

Sui的最初的协议开发者设计了可扩展的网络&#xff0c;通过水平扩展的方式来保持可负担得起的gas费用。其他区块链与之相比&#xff0c;则使用稀缺性和交易成本来控制网络活动。 Sui主网上线前90天的数据指标证明了这一设计概念&#xff0c;在保持100&#xff05;正常运行的同…...

RabbitMQ 安装教程

RabbitMQ 安装教程 特殊说明 因为RabbitMQ基于Erlang开发&#xff0c;所以安装时需要先安装Erlang RabbitMQ和Erlang版本对应关系 查看地址&#xff1a;www.rabbitmq.com/which-erlan… 环境选择 Erlang: 23.3及以上 RabbitMQ: 3.10.1Windows 安装 1. 安装Erlang 下载地…...

STM32F429IGT6使用CubeMX配置GPIO点亮LED灯

1、硬件电路 2、设置RCC&#xff0c;选择高速外部时钟HSE,时钟设置为180MHz 3、配置GPIO引脚 4、生成工程配置 5、部分代码 6、实验现象...

DOM的节点操作+事件高级+DOM事件流+事件对象

一.节点操作 1.父节点: node.parentNode 得到的是离元素最近的父级节点 2.子节点: parentNode.childNodes 所有的子节点 包含元素节点 文本节点等等parentNode.children (非标准) 获取所有的子元素节点,实际开发常用 parentNode.firstChild 获取…...

云端剪切板,让你的数据同步无界

云端剪切板&#xff0c;让你的数据同步无界&#xff01; 每个人都应该保护自己的数据&#xff0c;同时使它易于访问和共享。这就是我们的云剪切板网站诞生的原因&#xff01;无论你在哪里&#xff0c;只要登录我们的网站&#xff0c;就可以随时随地使用你的剪切板数据。 你可…...

Location匹配与Rewrite重写

一、常见的Nginx正则表达式 ^ &#xff1a;匹配输入字符串的起始位置 $ &#xff1a;匹配输入字符串的结束位置 * &#xff1a;匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”&#xff1a;匹配前面的字符一次或多次。如“ol”能匹配“ol”及“oll”、“oll…...

Docker源码阅读 - goland环境准备

docker 源码分为两部分 cli 和 moby&#xff08;docker&#xff09; tips: docker是从moby拷贝过去的&#xff1b;docker整体是一个C-S架构&#xff0c;cli客户端&#xff0c;docker服务端 docker-ce&#xff1a;https://github.com/docker/docker-ce cli&#xff1a;https://…...

数据库信息速递 -- MariaDB 裁员后,前景不确定 (翻译)

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加 liuaustin3微信号 &#xff0c;在新加的朋友会分到3群&#xff…...

4.1 Windows终端安全

数据参考&#xff1a;CISP官方 目录 安全安装保护账户安全本地安全策略安全中心系统服务安全其他安全设置软件安全获取 一、安全安装&#xff08;以安装windows系统为例&#xff09; 选择合适的版本 商业版本&#xff1a;家庭版、专业版、专业工作站版、企业版特殊版本&…...

win10强制卸载奇安信天擎

1、win r 打开运行 2、输入msconfig进入系统配置面板 3、点击引导&#xff0c;修改安全引导配置项 4、重启系统&#xff08;桌面会变成纯黑背景&#xff0c;符合预期&#xff0c;莫紧张&#xff09; 5、删除安装的文件夹 若是安装天擎时选择的自定义安装&#xff0c;则配置…...

npm常用命令

npm -v&#xff1a;查看 npm 版本 npm init&#xff1a;初始化后会出现一个 Package.json 配置文件&#xff0c;可以在后面加上 -y&#xff0c;快速跳到问答界面 npm install&#xff1a;会根据项目中的 package.json 文件自动给下载项目中所需的全部依赖 npm insall 包含 -…...

(一)创建型设计模式:4、原型模式(Prototype Pattern)

目录 1、原型模式的含义 2、C实现原型模式的简单实例 1、原型模式的含义 通过复制现有对象来创建新对象&#xff0c;而无需依赖于显式的构造函数或工厂方法&#xff0c;同时又能保证性能。 The prototype pattern is a creational design pattern in software development. …...

【算法学习】高级班九

这种互为旋变串&#xff1a; 给定两个字符串&#xff0c;判断是否互为旋变串 代码&#xff1a; 打表法&#xff1a; 每一层内的数字不互相依赖&#xff0c;只依赖它下面的层但实际上size会约束L1和L2的值&#xff0c;即L1和L2<N-size 思路&#xff1a;设置一个窗口…...

数据安全加固:深入解析滴滴ES安全认证技术方案

前文分别介绍了滴滴自研的ES强一致性多活是如何实现的、以及如何提升ES的性能潜力。由于ES具有强大的搜索和分析功能&#xff0c;同时也因其开源和易于使用而成为黑客攻击的目标。近些年&#xff0c;业界ES数据泄露事件频发, 以下是一些比较严重的数据泄露案件&#xff1a; 202…...

Typescript第九/十章 前后端框架,命名空间和模块

第九章 前后端框架 9.1 前端框架 Typescript特别适合用于开发前端应用。Typescript对JSX有很好的支持&#xff0c;而且能安全地建模不可变性&#xff0c;从而提升应用的结构和安全性&#xff0c;写出的代码正确性高&#xff0c;便于维护。 9.1.1 React JSX/TSX内容等 详情…...

LLM - argparse 解析脚本参数

目录 一.引言 二.argparse 解析 shell 参数 1.使用步骤 2.python 侧示例 3.shell 侧示例 一.引言 CUDA_VISIBLE_DEVICES0 python src/train_bash.py \--stage pt \--model_name_or_path path_to_your_model \--do_train \--dataset wiki_demo \--template default \--fin…...

谈一谈在两个商业项目中使用MVI架构后的感悟

作者&#xff1a;leobertlan 前言 当时项目采用MVP分层设计&#xff0c;组员的代码风格差异也较大&#xff0c;代码中类职责赋予与封装风格各成一套&#xff0c;随着业务急速膨胀&#xff0c;代码越发混乱。试图用 MVI架构 单向流 形成 掣肘 带来一致风格。 但这种做法不够以…...

ApacheCon - 云原生大数据上的 Apache 项目实践

Apache 软件基金会的官方全球系列大会 CommunityOverCode Asia&#xff08;原 ApacheCon Asia&#xff09;首次中国线下峰会将于 2023 年 8 月 18-20 日在北京丽亭华苑酒店举办&#xff0c;大会含 17 个论坛方向、上百个前沿议题。 字节跳动云原生计算团队在此次 CommunityOve…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...

Appium下载安装配置保姆教程(图文详解)

目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...

C++11 constexpr和字面类型:从入门到精通

文章目录 引言一、constexpr的基本概念与使用1.1 constexpr的定义与作用1.2 constexpr变量1.3 constexpr函数1.4 constexpr在类构造函数中的应用1.5 constexpr的优势 二、字面类型的基本概念与使用2.1 字面类型的定义与作用2.2 字面类型的应用场景2.2.1 常量定义2.2.2 模板参数…...