2025年4月11日学习记录
蓝桥算法回顾
一些函数与算法
1.字符串相关函数
截取字符串 str=s.substr(开始位置,截取长度) ;
插入字符串 str=s.insert(开始位置,插入字符串) ;
查找字符串 tmp=s.find(查找串,开始查找位置) ;
删除字符串 s.erase(开始位置,删除长度) ;
输入一行 getline(cin,字符串名) ;
2.STL回顾
容器
vector定义:vector<int> v(n,x);长度为n,初始化为x。
迭代器定义:vector<int>::iterator it;
栈定义:stack<int> st;
队列定义:queue<int> q;
大根堆定义:priority_queue<int> q;
小根堆定义:priority_queue<int,vector<int>,greater<int> > q;
map定义:map<int,int> mp;
map使用二分函数,查找比较的是第一个属性,返回迭代器。
pair定义:pair<int,int> p;
pair赋值:x=make_pair(1,2)或x={1,2}
pair使用:a=x.first,b=x.second;
无序map定义:unordered_map<int,int> m;
map查找为\(O(log n)\),无序map查找为\(O(1)\)。
算法
翻转:reverse(a,a+5)
第k个有序:nth_element(a,a+k,a+5)
下一个排列:next_permutation(a,a+5)
上一个排列:prev_permutation(a,a+5)
3.二分
bool check(int x){
}
int er(int l,int r){
while(l<r){
int mid=(l+r)>>1;
if(check(mid)){
ans=mid,l=mid+1;
}else r=mid;
}
return ans;
}
4.并查集
并查集数组需要初始化,fa[i]=i。
int find(int x){//查询是否是同一个集合
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void join(int x1,int x2){
int f1=find(x1),f2=find(x2);
if(fa[x1]!=fa[x2]) fa[x1]=x2;
}
5.DFS
void dfs(int k){//k代表递归层数,或者填第几个空
if(所有空已经填完){
判断最优解/记录答案;
return;
}
for(枚举这个空能填的选项){
if(这个选项合法){
保存现场;
dfs(k+1);
恢复现场;
}
}
}
6.ST表
ST表(Sparse Table,稀疏表)是用于解决 可重复性贡献问题 (区间最值、区间gcd……重复计算不会对贡献有变化)的数据结构,倍增+动态规划的思想。
状态:\(F[i][j]\) 代表以 \(i\) 为起点,长度为 \(2^j\) 的区间最大值,即区间 \([i,i+2^j-1]\) 的最大值
初始化:\(F[i][0]=a[i]\)
转移方程:
\[F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1])\]区间\([L,R]\) 的最大值:
\[len =R-L+1;log Len= \lfloor log(len) \rfloor\] \[ans=max(F[L][log Len],F[R-(1<<log Len)+1][log Len])\]代码:
//初始化
for(int i=1;i<=n;i++) cin>>f[i][0];
//状态转移
for(int j=1;j<=log2(n);j++)
for(int i=1;i<=n-(1<<j)+1;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
//查询
int l,r;cin>>l>>r;
int len=log2(r-l+1);
int ans=min(f[l][len],f[r-(1<<len)+1][len]);
cout<<ans<<" ";
7.倍增LCA
我采用常用的邻接表存储,链式前向星网上有很多。
#include<bits/stdc++.h>
using namespace std;
const int N=500005;
const int dep=20;
int fa[N][dep];
vector<int> e[N];//邻接表
int depth[N];
int n,m,s;
int maxdepth=0;
//dfs遍历无向图,确定各个结点的深度depth,树的深度maxdepth,父亲结点fa[i][0]
void dfs(int x,int y){
for(int i=0;i<e[x].size();i++){
if(e[x][i]==y) continue;
depth[e[x][i]]=depth[x]+1;//记录深度
maxdepth=max(maxdepth,depth[e[x][i]]);//更新树深
fa[e[x][i]][0]=x;//2^0倍父亲结点
dfs(e[x][i],x);
}
}
//初始化倍增结点fa[x][i]
void init(int x){
for(int i=0;i<dep;i++) fa[x][i]=0;
//为0表示不存在2^k倍父亲结点
for(int j=1;j<=log2(maxdepth);j++){
for(int i=1;i<=n;i++){
if(i==x) continue;
//i的2^j倍父节点是不是i的2^j-1倍父节点的2^j-1倍的父节点
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
//查找结点x,y的最近公共祖先
int find(int x,int y){
if(depth[x]>depth[y]) swap(x,y);
while(depth[y]>depth[x]){//找到同一深度的点
int len=log2(depth[y]-depth[x]);
y=fa[y][len];
}
if(x==y) return x;//点相同,为最近祖先
for(int i=log2(depth[y]);i>=0;i--){
if(fa[x][i]!=fa[y][i]){//不断寻找最近公共祖先
x=fa[x][i],y=fa[y][i];
}
}
return fa[x][0];
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>s;
int u,v;
for(int i=1;i<n;i++){
cin>>u>>v;
e[u].push_back(v);//构造无向图
e[v].push_back(u);
}
depth[s]=0;//初始根结点深度为0
dfs(s,-1);
init(s);//初始化
while(m--){
cin>>u>>v;
cout<<find(u,v)<<"\n";
}
return 0;
}

