学习总结:本周学习了最小生成树、线段树、博弈、扩展欧几里得、stl、逆元、同余、费马小定理等知识。
最小生成树中学了两种方法,Kruskal算法和Pirm算法。其中Kruskal算法有一部分采用了并查集的算法,因此学习起来相对较轻松。Prim算法则是一个新的思路,不过理解后多敲几遍也可以逐渐掌握了。
Prim核心代码:
//vis数组标记是否加入生成树,dis数组标记各点到生成树的距离,p为邻接矩阵
for(int i=0;i<=n;i++){
dis[i]=inf;
}//初始化数组
dis[0]=0;//选择一个初始点
for(int i=0;i<n+1;i++){
int v=-1;
for(int j=0;j<=n;j++){
if(f[j]==0&&(v==-1||dis[j]<dis[v])){
v=j;
}
}//寻找最近的点,记录位置
f[v]=1;
for(int k=0;k<=n;k++){
dis[k]=min(dis[k],p[v][k]);
}//判断是否进行松弛
}
线段树较最小生成树难了许多(痛苦的开始,线段树可以执行区间求和、单点修改、区间修改等一系列问题,同样的,代码也更复杂,需要多加思考。
首先建树:
void pushup(int rt){
tre[rt].sum=tre[rt*2].sum+tre[rt*2+1].sum;
} //从下往上传递区间值,求和
void build(int rt,int l,int r){
if(l==r){
tre[rt]={l,r,a[l]};
}
else{
tre[rt]={l, r};
int mid=tre[rt].mid();
build(rt*2,l,mid); //递归左儿子
build(rt*2+1,mid+1,r); //递归右儿子
pushup(rt);
}
}
查询功能:(查询并求和的码
int query(int rt,int l,int r){
if(tre[rt].l>=l&&tre[rt].r<=r){
return tre[rt].sum;
}
else{
int mid=tre[rt].mid();
int ans=0;
if(l<=mid)
ans+=query(rt*2,l,r);
if(r>mid)
ans+=query(rt*2+1,l,r);
return ans;
}
}
运用懒标记的区间修改:
void pushdown(int rt){
if(tre[rt].lazy){
tre[rt*2].lazy+=tre[rt].lazy; //左
tre[rt*2+1].lazy+=tre[rt].lazy;
tre[rt*2].sum+=(tre[rt*2].r-tre[rt*2].l+1)*tre[rt].lazy; //左
tre[rt*2+1].sum+=(tre[rt*2+1].r-tre[rt*2+1].l+1)*tre[rt].lazy;
tre[rt].lazy=0; //清空标记!
}
}
void modify(int rt,int l,int r,long long pos){
if(tre[rt].l>=l&&tre[rt].r<=r){ //查看区间是否被包含,包含就直接修改
tre[rt].sum+=(tre[rt].r-tre[rt].l+1)*pos;
tre[rt].lazy+=pos;
}
else{
pushdown(rt);
int mid=tre[rt].mid();
if(l<=mid)
modify(rt*2,l,r,pos);
if(r>mid)
modify(rt*2+1,l,r,pos);
tre[rt].sum=tre[rt*2].sum+tre[rt*2+1].sum;
}
}
博弈讲了巴什博弈、威佐夫博弈、斐波那契博弈等,把结论多记几遍。
剩下的数论知识在证明的过程中有些难理解,多加思考。
有所反思:寒假集训由于疫情改为在家学习,但是因为在家学习,在学习态度上有所懈怠,没有像在学校一样精力集中,娱乐时间也较在学校长,存在划水现象。下一周应有所改进。有不会的知识要及时上网搜索或者找同学学长进行解答,尽量不要造成不懂的知识的积累。