浅说线性差分和树上差分

news/2025/3/22 21:30:10/文章来源:https://www.cnblogs.com/LIM-41/p/18777364

目录
  • 线性差分
    • 正常思路
    • 差分思路
    • 二维差分的定义
    • 二维差分的解释
    • 例题1 地毯
  • 树上差分引入
  • 点差分
    • 例题1——wwx的出玩
      • 分析与解答
    • 例题2——松鼠的新家
      • 分析与解答
  • 边差分
    • 例题1——边差分模版
      • 分析与解答
    • 例题2——运输计划
      • 分析与解答

线性差分

当我们这里有\(n\)个数,现在我要对其中一段进行操作,每次可能加上一个数,也有可能减去一个数,请输出最终的数列。
(\(0\le n \le 10^6\))

正常思路

我们正常来看,如果想要对一个区间进行操作,我们只能遍历这个区间,一个一个的去修改,但是这样的的时间复杂度是\(O(n^2)\),是过不了的,所以我们要换个思路。(当然如果你只想骗点分也是可以的

#include<bits/stdc++.h>
using namespace std;
const int INF=1e7;
int a[INF]
int main(){int n,m;cin>>n>>m;for (int i=1;i<=n;i++){cin>>a[i];}for (int i=1;i<=m;i++){int l,r,x;cin>>l>>r>>x;for (int j=l;j<=r;j++){a[j]+=x;}}for (int i=1;i<=n;i++){cout<<a[i]<<" ";}return 0;
}

差分思路

虽然我不知道这个思路是怎么来的,但是不重要,它其实就是一个思想,也就是利用以小带大的思想去操作。
差分就是对相邻的两个数求差值,然后这些差值的前缀和就是这个数,也就是前缀和是差分的逆运算。我们可以来看一个例子:
在这里插入图片描述
此时差分数组的前缀和就是原数组,当我们要修改一个区间时,只需要更改差分数组对应区间的首相和最后一项的下一位的值就行了。比如我们想要更改2~4这个区间的值,我们只需要将第三位的-3+1,并且将第五位的-2-1就行了,这样我们在进行前缀和的时候就不会多加一段了。
因此,我们得到了区间修改的核心代码

//ans表示差分数组
void change(int l,int r,int x){ans[l]+=x;ans[r+1]-=x;return;
}

下面我们将以一道例题,来给大家称述完整的代码

Descirption
输入一个长度为 n 的整数序列。
接下来输入 m 个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r] 之间的每个数加上 c。
请你输出进行完所有操作后的序列。

分析题意后发现,这就是最简单的最标准的差分,话不多说,直接上代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=200000+1000;
long long a[INF],b[INF];
int main(){int n,m;cin>>n>>m;for (int i=1;i<=n;i++){cin>>a[i];b[i]=a[i]-a[i-1];//计算差分数组}for (int i=1;i<=m;i++){int l,r,c;cin>>l>>r>>c;b[l]+=c;//核心代码b[r+1]-=c;}for (int i=1;i<=n;i++){b[i]+=b[i-1];//计算前缀和cout<<b[i]<<" ";}return 0;
}

我们还是老样子,上例题。

在这里插入图片描述
虽然我很想说,我不能帮帮她,分析题意可知,这也是一道一模一样的差分裸题,我们只需要在最后求解前缀和的时候,找个最小值就行了,一点也不难。

#include<bits/stdc++.h>
using namespace std;
const int INF=5*1e6+10;
int a[INF],b[INF];
int minn=INT_MAX;
int main(){int n,p;cin>>n>>p;for (int i=1;i<=n;i++){cin>>a[i];b[i]=a[i]-a[i-1];} for (int i=1;i<=p;i++){int x,y,z;cin>>x>>y>>z;b[x]+=z;b[y+1]-=z;}for (int i=1;i<=n;i++){b[i]+=b[i-1];minn=min(b[i],minn);}cout<<minn;return 0;
}

在这里插入图片描述
这道题很有意思,在洛谷上是道绿题 题目传送门

因为是区间整体加减1,所以我们很自然的就可以想到用差分求解。

这道题可以看做求出原序列的差分之后,将 S[2...n] 全部变为0所需的最少的步数和可以使 S[1] 变为多少种不同的数。

很明显的,在我们求出的差分数组中,有正数也有负数,要消除这些数,使得它们全部归零,我们有以下3种可行的操作:

选取一个正数(X)和一个负数(Y),使正数减1,负数加1,这样经过N次操作,我们一定可以以最少的代价将绝对值较小的一方归零,代价为\(abs(min(X,Y))\)
选取一个正数(X),使其与 S[1] 配对,这样,我们经过N次操作,一定可以将它归零,代价为:abs(X)
选取一个负数(Y),使其与 S[n+1] 配对,这样,我们经过N次操作,一定可以将它归零,代价为:abs(Y)
经过上述分析,我们就能够推导出本题的解题公式:

\[ans=abs(min(X,Y))+abs(X−Y) \]

也就是

\[ans=abs(max(X,Y)) \]

需要注意的是这里的X,Y是差分数组中所有正数的和与所有负数的和的绝对值
最后我们还要求能构成几组解,这很容易可以推出:

\[ans=abs(X−Y)+1 \]

那么我们就可以直接写啦!

#include<bits/stdc++.h>
using namespace std;
const int INF=1e5+10;
long long a[INF];
long long ans1,ans2;
int main(){int n;cin>>n;for (int i=1;i<=n;i++){cin>>a[i];if (i==1)continue;long long c=a[i]-a[i-1];//求解差值if (c>0)ans1+=c;//判断是正是负else ans2+=abs(c);}cout<<max(ans1,ans2)<<endl;cout<<abs(ans1-ans2)+1;return 0;
}

我们上节课学了一维的差分,但其实还有二维差分,只是比较难写。

二维差分的定义

二维差分是指对于一个n*m的矩阵a,要求支持操作pro(x1,y1,x2,y2,a),表示对于以(x1,y1)为左上角,(x2,y2)为右下角的矩形区域,每个元素都加上常数a。求修改后的矩阵a。

二维差分的解释

这样说似乎还是有点抽象,我们不妨以一道例题来看看

在 n×n 的格子上有 m 个地毯。
给出这些地毯的信息,问每个点被多少个地毯覆盖。

其实不难发现,这个和普通的递推好像有点相似之处,我们其实可以画个图来解释一下本图来源于网络
注:上图来源于网络

不难发现,二维差分的关键就是在于:

mp[x1][y1]++;
mp[x1][y2+1]--;
mp[x2+1][y1]--;
mp[x2+1][y2+1]++;

所以我们直接上例题吧

例题1 地毯

在 n×n 的格子上有 m 个地毯。
给出这些地毯的信息,问每个点被多少个地毯覆盖。

这道题是十分简单的差分,直接套公式就行了

#include<bits/stdc++.h>
using namespace std;int mp[2100][2100];
int main(){int n,m;cin>>n>>m;for (int i=1;i<=m;i++){int x1,x2,y1,y2; cin>>x1>>y1>>x2>>y2;mp[x1][y1]++;mp[x1][y2+1]--;mp[x2+1][y1]--;mp[x2+1][y2+1]++;}for (int i=1;i<=n;i++){for (int j=1;j<=n;j++){mp[i][j]+=mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1];cout<<mp[i][j]<<" ";}cout<<endl;}return 0;
}

现在的话我们就把他放到树上来做。因为这是树,所以会有点和边之分,所以树上差分也会分为 点差分边差分

树上差分引入

树上差分其实和线性差分没有什么区别,只不过是放到了树上的两点,而他们之间的最简路径就是可以类比成线性的两点之间的线段。
在这里插入图片描述
所以我们如果要对一条曲线进行操作的话,就是在树上跑差分,那么树上差分数组究竟是什么呢,他又代表着什么意思呢?这是一个值得深思的问题,也是困扰我很久的问题。

树上差分数组本质上存储的是 操纵方式,而不是简单的差值。例如一个点 \(x\) 的差分数组 \(p[x]=-3\) 代表这个点或这个点所对应的边被减去了3,而不是这个点或这个边等于-3,这是一个易错也易混的点。

相同的,对线性差分数组进行求前缀和的话,我们就可以得到真实的答案的值,那么类似的,在 树上差分数组中求子树和,就可以的到这个点的操纵方式,不过为什么要求子树和,而不求其它的,我也不知道,我也不敢问。
在这里插入图片描述

点差分

如果我们现在要对树上的一条路径上的点进行统一操作,比如说 +1 或 -2,我们应该如何完成?
首先是不是很容易想到暴力 dfs ?但是这样的时间复杂度是 \(\cal O(n^2)\) 的,不优秀。但是我们在学什么,是不是在学差分,那为什么不从差分的视角来考虑考虑?

如果我们要对一条 \(A \rightarrow B\) 的路径进行+1的修改操作,那么首先我们肯定要在点 \(A\)\(B\) 两个位置进行修改对吧,又因为我们最后是通过求子树和来求得每个点的修改方式,所以不能影响 点 \(A\) 和 点 \(B\) 所对应的子树,所以我们可以非常明了的得到

\[p[A]++,p[B]++ \]

然后我们的目光不断向上看,发现基本上都没有问题,但是在他们的最近公共祖先那里除了岔子,为什么呢?因为二者是从两端慢慢爬上来的,这就会导致他们的 LCA 会被增加两次,所以我们又可以得到

\[p[lca(A,B)]-- \]

我们继续往上看,发现点 \(A\) 和点 \(B\) 的最近公共祖先的父亲在计算子树和的时候任然会被增加一次,但是他应该是不能被修改的,所以我们还可以得到

\[p[fa(lca(A,B))]-- \]

继续往上看,发现没有问题了,说明我们的操作就成功的完成了!(看不懂的,看下面的图示)
在这里插入图片描述
我们把上述的公式总结一下就是 两个点自己加,他们的lca和lca的爸爸都要减,把它写成代码就是

//dp 为倍增数组,lca为求最近公共祖先的函数
int root=lca(a,b);
p[a]++,p[b]++;
p[root]--,p[dp[root][0]]--;

那么当我们要求所有的答案的时候,也就是要求子树和的时候,我们就可以使用一个时间复杂度为 \(\cal O(n)\) 的 dfs 函数来求解:

//mp为邻接表存储
void get(int x, int fa) {int len = mp[x].size();for (int i = 0; i < len; i++) {if (mp[x][i] == fa) continue;int t = mp[x][i];get(t, x);p[x] += p[t];//差分数组求子树和}
}

看完后是不是感觉非常简单,就只是在树上倍增的基础上对一个数组进行了一点点操作,那么好,我们上实战!

例题1——wwx的出玩

wwx给她的衣柜的有 n 个隔间,隔间编号为1到 n 。她有 k 天要和她的男朋友出去玩,第 i 次玩耍wwx会穿隔间 si 到隔间 ti 的衣服,每次穿这些衣服,都会给它们带来一个单位的损坏,你作为她的男朋友,请计算损坏程度最大的衣服的损坏程度是多少。

分析与解答

不难发现,这道题就是一道裸的点差分问题,所以我们直接套模板,顺便也把模板给你了。

#include<bits/stdc++.h>
using namespace std;
const int INF=1e5;
vector<int> mp[INF];
int ans,dp[INF][20],deep[INF],num[INF];//num为差分数组void prepare(int x,int fa){for (int j=1;(1<<j)<=deep[x]-1;j++){dp[x][j]=dp[dp[x][j-1]][j-1];} int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i]==fa)continue;int t=mp[x][i];deep[t]=deep[x]+1,dp[t][0]=x;prepare(t,x); }
}int lca(int x,int y){if (deep[x]<deep[y])swap(x,y);int index=__lg(deep[x]-deep[y]);for (int i=index;i>=0;i--){if (deep[dp[x][i]]>=deep[y])x=dp[x][i];if (deep[x]==deep[y])break;}if (x==y)return x;for (int i=18;i>=0;i--){if (dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0];
}void get(int x,int fa){int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i]==fa)continue;int t=mp[x][i];get(t,x);num[x]+=num[t];}ans=max(ans,num[x]);//求得最大值
}
int main(){int n,k;cin>>n>>k;for (int i=1;i<n;i++){int u,v;cin>>u>>v;mp[u].push_back(v);mp[v].push_back(u);} deep[1]=1;prepare(1,-1);for (int i=1;i<=k;i++){int s,t;cin>>s>>t;int root=lca(s,t);num[s]++,num[t]++,num[root]--,num[dp[root][0]]--;}get(1,-1);cout<<ans;return 0;
}

例题2——松鼠的新家

题目传送门

分析与解答

这道题其实也是裸题,我们稍微分析一下就知道它的那个参观路线是可以被分成多个区间修改的,但是这样的话,他们的端点的位置,会被重复计算,所以要特判

#include<bits/stdc++.h>
using namespace std;
const int INF=3e5+10;
vector<int> mp[INF];
int ans,dp[INF][20],deep[INF];
int a[INF],num[INF];void prepare(int x,int fa){for (int j=1;(1<<j)<=deep[x]-1;j++){dp[x][j]=dp[dp[x][j-1]][j-1];} int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i]==fa)continue;int t=mp[x][i];deep[t]=deep[x]+1,dp[t][0]=x;prepare(t,x); }
}int lca(int x,int y){if (deep[x]<deep[y])swap(x,y);int index=__lg(deep[x]-deep[y]);for (int i=index;i>=0;i--){if (deep[dp[x][i]]>=deep[y])x=dp[x][i];if (deep[x]==deep[y])break;}if (x==y)return x;for (int i=18;i>=0;i--){if (dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0];
}void get(int x,int fa){int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i]==fa)continue;int t=mp[x][i];get(t,x);num[x]+=num[t];}ans=max(ans,num[x]);
}
int main(){int n;cin>>n;for (int i=1;i<=n;i++){scanf("%d",&a[i]);}for (int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);mp[u].push_back(v);mp[v].push_back(u);} deep[1]=1;prepare(1,-1);for (int i=1;i<n;i++){int s=a[i],t=a[i+1];int root=lca(s,t);num[s]++,num[t]++,num[root]--,num[dp[root][0]]--;}get(1,-1);for (int i=2;i<=n;i++){num[a[i]]--;}for (int i=1;i<=n;i++){printf("%d\n",num[i]);}return 0;
}

边差分

其实这种差分的思路和点差分的思路差不多,只不过因为是边,所以我们不能直接操作,因此我们要把这个边放到这条边所连接的两个点中的更深一层的点。(例如:\(deep[x]<deep[y] \rightarrow p[y]=mp[x][y]\)
我们还是一步一步的推,相信在有上节课中教你的推导方式,这个公式也是呼之欲出的,所以我就不做示范了,下来你可以自己试试。

//lca为找最大公共祖先的函数
int root=lca(x,y);
p[x]++,p[y]++;
p[root]-=2;

这个的话,总结一下就是 两个点自己加,他们的祖先减两倍
至于求得最后的答案,也是和点差分是一样的,所以就不做过多的赘述了。

例题1——边差分模版

给出一棵n个点的树,每条边有一个边权,给定m个操作u,v,x,表示把u-->v这条边的边权增加x,最后询问最大的边权。

分析与解答

其他不说,也是非常简单的一道模版题,所以直接就给代码了,也算是把模版给你们了。

#include<bits/stdc++.h>
using namespace std;
const int INF=2e5+10;
struct Node{int point,num;
};
vector<Node> mp[INF];
long long a[INF],p[INF],ans=INT_MIN;
long long deep[INF],dp[INF][20];void prepare(int x,int fa){for (int j=1;(1<<j)<=deep[x]-1;j++){dp[x][j]=dp[dp[x][j-1]][j-1];}int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i].point==fa)continue;int t=mp[x][i].point;a[t]=mp[x][i].num;dp[t][0]=x,deep[t]=deep[x]+1;prepare(t,x);}
}int lca(int x,int y){if (deep[x]<deep[y])swap(x,y);int index=__lg(deep[x]-deep[y]);for (int i=index;i>=0;i--){if (deep[dp[x][i]]>=deep[y])x=dp[x][i];if (deep[x]==deep[y])break;}if (x==y)return x;for (int i=18;i>=0;i--){if (dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0];
}void get(int x,int fa){int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i].point==fa)continue;int t=mp[x][i].point;get(t,x);p[x]+=p[t];} ans=max(ans,p[x]+a[x]);
}
int main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);int n,m;cin>>n>>m;for (int i=1;i<n;i++){int u,v,x;cin>>u>>v>>x;mp[u].push_back({v,x});mp[v].push_back({u,x}); }deep[1]=1;prepare(1,-1);for (int i=1;i<=m;i++){int u,v,x;cin>>u>>v>>x;int root=lca(u,v);p[u]+=x,p[v]+=x,p[root]-=2*x;}get(1,-1);cout<<ans;return 0;
}

例题2——运输计划

题目传送门

分析与解答

首先请注意哈,在进入提高组以后,算法一般情况下是不会出现的模版题或者是单独的一种算法的,一般情况都是把很多种算法融合在一起来考,所以我们思路也要多方面的入手。
首先拿到这个题,把题面看完以后,就会发现这是一道最大值最小的问题,那么自然而然的就要使用二分答案,那么接下来就是如何check的问题。
因为我们二分的是最终的答案,所以但是每一次运输的距离有长有短,因此我们要从中找到不符合当前答案的路径有哪些,有多少,并且通过一种标记手段表示这条路径是要被减去一定长度的,那么这种标记手段我们就可以用到差分。
在这里插入图片描述

现在我们已经找到了所有的不符合条件的路径了,但是题目中要求了只能对一条边开虫洞,所以我们还要找到到底要开那条边,那么怎么找呢?
这时候差分数组有排上用场了,不难发现,如果我们对差分数组进行求子树的操作时,每条边所对应的点的差分值就是当前边被多少条边经过的,这是非常显然的对吧!那么我们是不是只需要在求子树和的时候,判断一下当前点是否被所有边经过不就行了吗?然后从这些边中选一条最大的边来开虫洞,是不是就行了?
最后我们在让所有路径中最大的一条来减去当前选取的最大的一条所的得到的值来和当前所二分到的答案进行判断,是不是就可以了?思路讲完了,但是还是有一些细节上的东西我就不在这里细说了,自己看代码吧,我会尽量的注释详细的。

#include<bits/stdc++.h>
using namespace std;
const int INF=3e5+10;struct Node{int point,num;
};
vector<Node> mp[INF];
int a[INF],b[INF],dp[INF][30],w[INF][30],p[INF],edge[INF];
int deep[INF],dis[INF];
int maxlen=INT_MIN,maxtot=INT_MIN,ans=INT_MAX;
int maxn=0,tim=0;
void prepare(int x,int fa){for (int j=1;(1<<j)<=deep[x]-1;j++){dp[x][j]=dp[dp[x][j-1]][j-1];w[x][j]=w[dp[x][j-1]][j-1]+w[x][j-1];//维护树上距离}int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i].point==fa)continue;int t=mp[x][i].point;edge[t]=mp[x][i].num;//存储以t结尾的那条边deep[t]=deep[x]+1,dp[t][0]=x,w[t][0]=mp[x][i].num;prepare(t,x); }
}int lca_length(int x,int y){int tot=0;if (deep[x]<deep[y])swap(x,y);int index=__lg(deep[x]-deep[y]);for (int i=index;i>=0;i--){if (deep[dp[x][i]]>=deep[y])tot+=w[x][i],x=dp[x][i];if (deep[x]==deep[y])break;}if (x==y)return tot;for (int i=20;i>=0;i--){if (dp[x][i]!=dp[y][i])tot+=w[x][i]+w[y][i],x=dp[x][i],y=dp[y][i];}tot+=w[x][0]+w[y][0];return tot;
}int lca_root(int x,int y){if (deep[x]<deep[y])swap(x,y);int index=__lg(deep[x]-deep[y]);for (int i=index;i>=0;i--){if (deep[dp[x][i]]>=deep[y])x=dp[x][i];if (deep[x]==deep[y])break;}if (x==y)return x;for (int i=20;i>=0;i--){if (dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0];
}void get(int x,int fa){int len=mp[x].size();for (int i=0;i<len;i++){if (mp[x][i].point==fa)continue;int t=mp[x][i].point;get(t,x);p[x]+=p[t];}if (p[x]==tim)maxn=max(maxn,edge[x]);//如果当前点的差分值等于不符合条件的值,那么就取最大值
} int main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);int n,m;cin>>n>>m;for (int i=1;i<n;i++){int u,v,w;cin>>u>>v>>w;mp[u].push_back({v,w});mp[v].push_back({u,w});maxlen=max(maxlen,w);//找到最大的边来求上下边界的值}deep[1]=1;prepare(1,-1);for (int i=1;i<=m;i++){cin>>a[i]>>b[i];dis[i]=lca_length(a[i],b[i]);//维护路径maxtot=max(dis[i],maxtot);//找到最大的路径来求上下边界的值}int l=maxtot-maxlen,r=300000000;while (l<=r){maxn=0,tim=0;memset(p,0,sizeof(p));int mid=(l+r)>>1;for (int i=1;i<=m;i++){if (dis[i]>mid){//不符合条件,开始差分int root=lca_root(a[i],b[i]);p[a[i]]++,p[b[i]]++,p[root]-=2;tim++;//记录次数}}if (tim==0){//如果都符合,那么当前答案自然可以ans=mid;r=mid-1;continue; }get(1,-1);//求子树和if (maxtot-maxn<=mid){//判断ans=mid;r=mid-1;}else l=mid+1;}cout<<ans;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/903608.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring 事务失效

场景1:代码:执行结果:异常抛出,但是数据没有回滚。 代理对象调用 b() 方法 没有开启事务:普通对象调用a() 方法开启事务:在b() 方法上加入事务注解,开启事务就没问题:本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/18787133

征程 6X CAMSYS 性能测试方案介绍

1.性能测试方法原理 CAMSYS 其性能指标主要包括:帧率、延迟,以及系统的 DDR 带宽、CPU 占用率等。 对于帧率、延迟,通过在驱动中创建 trace event,分别记录通路上的每个 IP,每帧开始处理(frame_start)和结束处理(frame_end)的时间戳信息和帧信息,来实现帧率计算和延迟…

数据结构2

概率论与数理统计1-基本概念 概率论与数理统计2-基本数据结构 概率论与数理统计3-基本数据处理技术 基本的数据结构 - 数据结构- 数据的逻辑结构- 线性结构- 线性表- 栈(特殊的线性表)- 队列(特殊的线性表)- 字符串- 数组- 广义表- 非线性结构- 树型结构- 图型结构- 数据的存储…

day7 刷牛客华为机试题+学java

https://www.nowcoder.com/exam/oj/ta?page=1&tpId=37&type=37 字符串 第一题:第二题: 省行版:逻辑版:java网课学习: 多态调用成员变量,编译看左边,运行也看左边。调用成员方法时,编译看左边,运行看右边。if(a instanceof Dog d) 导包final 修饰引用类型地址…

【Docker】MySQL、Reids、Mongodb、Nacos、RabitMQ安装指南

1 docker的下载 建议通过 火绒应用商店 或者 联想应用商店 下载 2 配置Docker 配置镜像站 https://docker.1panel.live {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": fa…

Web前端入门第 22 问:CSS 选择器一览

HTML 在语法上并无大小限制,所以其结构可以浩瀚无边,CSS 选择器的作用则是在这些复杂的 HTML 结构中进行元素定位。 示例代码 记住此代码,后面所有的 css 选择器都是基于此代码。 注意:代码中存在两个一样的 id="p1" 元素,仅为了演示效果,正常编码中请保证 id …

曼哈顿距离和切比雪夫距离

曼哈顿距离(Manhattan Distance) 解释:只能横着或竖着走,坐标上两点的距离 假设存在两点 \(A(x_1, y_1)\) \(B(x_2, y_2)\) \(dis(A, B) = |x_1 - x_2| + |y_1 - y_2|\)对于上方求曼哈顿距离的式子,有四种情况 \( \begin{cases} x_1 > x_2 & y_1 > y_2 & {…

如何设置家用威联通 NAS UPS 断电后自动关机并通知其他设备?

场景📝备注: 求轻喷, 求放过. 😅 我真的是个理线方面的白痴. 这已经是我的极限了. 😂我的家庭实验室 Homelab 服务器集群配置如下.上半部分之前已经介绍过了, 这里就不再赘述了. 今天重点介绍介绍 UPS 和 NAS 部分.1台 UPS, 型号为 APC Back-UPS 650. 插座插着: NAS 和 插…

[扫描线] 数据结构测试(2025.3.22)

暴力大赛,赛时暴力打满喜提80pts,可惜T1没想到暴力。 难度:T2<T1<T3.T1 第1题 团队 查看测评数据信息有n个工人,第i个工人的能力是v[i], 他只与能力在L[i]到R[i]之间的人在一起工作,问最多能选出多少人在一起工作。输入格式第一行,一个整数n, 1 <= n <…

centOS 上部署hadoop+mysql+hive 服务之hadoop安装

以下安装的hadoop版本是3.3.6 ,由于hadoop是运行于java环境,因此,需要提前安装java jdk并配置环境变量。 jdk的安装及配置: jdk8 国内下载路径:https://repo.huaweicloud.com/java/jdk/8u202-b08/ 可根据实际需要选择对应的jdk版本 1、下载jdkwget https://repo.huaweicl…

创建django视图和路由

第一个视图 from django.shortcuts import render from django.http import HttpResponse# Create your views here. def hello(request):msg = Hello World!!!return HttpResponse(msg)第一个路由 from django.urls import path from .views import hellourlpatterns = [path(…

8.4.3 基于循环神经网络的字符级语言模型

字符级语言模型的优缺点见下 好处:不用担心\(\left<\text{UNK}\right>\)的出现 坏处:最终的序列要长的多;训练也要复杂得多(对内存和速度的要求都要高得多) 现如今,人们一般使用单词级RNN,但是也有特殊情况会使用字符级RNN 在训练了一个RNN后,我们可以利用这个RN…