边界条件处理不好非常容易写挂
以简单的二分查找为例,有以下两种写法
点击查看代码
| 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; |
| } |
点击查看代码
| #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; |
| } |
点击查看代码
| #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; |
| } |
点击查看代码
| 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的本质就是贪心, 数组代表有没有被松弛过,每个点只会被松弛一次就能算出正确值。
点击查看代码
| 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 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效