整数二分
边界条件处理不好非常容易写挂
以简单的二分查找为例,有以下两种写法
点击查看代码
int bsearch(int x,int l,int r){ if(l>=r)return l; int mid=l+r>>1; if(a[mid]<x)return bsearch(x,mid+1,r); else return bsearch(x,l,mid);}
点击查看代码
int bsearch(int x,int l,int r){ if(l>=r)return l; int mid=(l+r+1)>>1; if(a[mid]<=x)return bsearch(x,mid,r); else return bsearch(x,l,mid-1);}
简单来说,首先需要知道计算 的时候是下取整的。
判断条件中取等号的那个需要保留 ,因此这时 ,防止当查询右子区间长度为 的时候造成死循环,例如 。
如果需要取等的一边在左子区间,那就不需要 ,因为会被下取整,不取等号不需要保留,所以直接 。
快速幂
点击查看代码
inline int power(int a,int b,int p){ long long ans=1; while(b) { if(b&1)ans=ans*a%p; a=a*a%p; b>>=1; } return ans;}
线段树
1
点击查看代码
#include<bits/stdc++.h>using namespace std;template<typename T>inline void re(T &x){ x=0; int f=1;char c=getchar(); while(!isdigit(c)) { if(c=='-')f=-1; c=getchar(); } while(isdigit(c)) { x=(x<<1)+(x<<3)+(c^48); c=getchar(); } x*=f;}template<typename T>inline void wr(T x){ if(x<0)putchar('-'),x=-x; if(x>9)wr(x/10); putchar(x%10^48);}const int N=1e6+1;struct SGT{ int l,r; long long val,tag;}tr[N<<2];int a[N],n,m,x,y,k,opt;long long calc(int x){ return tr[x].val+(tr[x].r-tr[x].l+1)*tr[x].tag;}void pd(int x){ tr[x<<1].tag+=tr[x].tag, tr[x<<1|1].tag+=tr[x].tag; tr[x].tag=0;}void pu(int x){ tr[x].val=calc(x<<1)+calc(x<<1|1);}inline void build(int x,int l,int r){ tr[x].l=l,tr[x].r=r; if(l==r) { tr[x].val=a[l];return; } int mid=l+r>>1; build(x<<1,l,mid),build(x<<1|1,mid+1,r); pu(x);}inline void modify(int x,int l,int r,int v){ if(l<=tr[x].l&&tr[x].r<=r) { tr[x].tag+=v; return; } pd(x); int mid=tr[x].l+tr[x].r>>1; if(l<=mid)modify(x<<1,l,r,v); if(r>mid)modify(x<<1|1,l,r,v); pu(x);}inline long long query(int x,int l,int r){ if(l<=tr[x].l&&tr[x].r<=r)return calc(x); pd(x); int mid=tr[x].l+tr[x].r>>1; long long ans=0; if(l<=mid)ans+=query(x<<1,l,r); if(r>mid)ans+=query(x<<1|1,l,r); pu(x); return ans;}void pre(){ re(n),re(m); for(int i=1;i<=n;i++)re(a[i]); build(1,1,n);}int main(){ pre(); while(m--) { re(opt); if(opt==1) { re(x),re(y),re(k); modify(1,x,y,k); } else { re(x),re(y); wr(query(1,x,y)),putchar('\n'); } } return 0;}
矩阵快速幂
点击查看代码
struct Matrix{ int n,m; int a[maxn][maxn]; Matrix(){memset(a,0,sizeof a);}};Matrix operator *(Matrix a,Matrix b){ Matrix tmp; tmp.n=a.n,tmp.m=b.m; for(int i=1;i<=a.n;++i) { for(int j=1;j<=b.m;++j) { for(int k=1;k<=a.m;++k) { tmp.a[i][j]=(tmp.a[i][j]+a.a[i][k]*b.a[k][j])%MOD; } } } return tmp;}Matrix base(int x){ Matrix tmp; tmp.n=tmp.m=x; for(int i=1;i<=x;++i)tmp.a[i][i]=1; return tmp;}Matrix power(Matrix a,int b){ Matrix ans=base(a.n); while(b) { if(b&1)ans=ans*a; a=a*a; b>>=1; } return ans;}
LCA
倍增
点击查看代码
#include<bits/stdc++.h>using namespace std;const int N=5e5+2;int F[N][22],dep[N];int n,m,s;vector<int> E[N];inline void dfs(int x){ for(int i=0;i<E[x].size();i++) { int v=E[x][i]; if(v==F[x][0])continue; F[v][0]=x,dep[v]=dep[x]+1; dfs(v); }}void pre(){ cin>>n>>m>>s; int u,v; for(int i=1;i<=n-1;i++) { cin>>u>>v; E[u].push_back(v),E[v].push_back(u); } dep[s]=1,dfs(s); for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) F[i][j]=F[F[i][j-1]][j-1]; }inline int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); for(int i=20;i>=0;i--) if(dep[F[x][i]]>=dep[y])x=F[x][i]; if(x==y)return x; for(int i=20;i>=0;i--) if(F[x][i]!=F[y][i])x=F[x][i],y=F[y][i]; return F[x][0];}int main(){ pre(); int u,v; while(m--) { cin>>u>>v; cout<<lca(u,v)<<endl; } return 0;}
树链剖分
最短路
Dijkstra
点击查看代码
inline void dijkstra(int s){ priority_queue< pair<int,int> > q; memset(dis,0x3f,sizeof dis); memset(vis,0,sizeof vis); dis[s]=0,q.push(make_pair(0,s)); while(q.size()) { int x=q.top().second;q.pop(); if(vis[x])continue; vis[x]=1; for(int i=head[x];i;i=E[i].nex) { int v=E[i].v; if(dis[v]>dis[x]+E[i].w) { dis[v]=dis[x]+E[i].w; if(!vis[v])q.push(make_pair(-dis[v],v)); } } }}
可以用堆进行优化,默认大根堆,直接push(-dis[v],v)就好了
DJ的本质就是贪心, 数组代表有没有被松弛过,每个点只会被松弛一次就能算出正确值。
SPFA
点击查看代码
inline void spfa(int x){ queue<int>q; memset(dis,0x7f,sizeof dis); memset(vis,0,sizeof vis); q.push(x);vis[x]=1;dis[x]=0; while(!q.empty()) { int x=q.front();vis[x]=0,q.pop(); for(int i=head[x];i;i=E[i].nex) { int v=E[i].v; if(dis[x]+E[i].w<dis[v]) { dis[v]=dis[x]+E[i].w; if(!vis[x])q.push(v),vis[v]=1; } } }}
注意spfa的vis数组代表是否在队列中,可以经过多次修改;而dij的vis数组代表是否松弛过,只会被修改一次
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步