OI模板(持续更新)
快速排序,时间——
void qsort(int l,int r){
if(l>=r) return ;
int i=l-1,j=r+1,mid=a[l+r>>1];
while(i<j){
while(a[++i]<mid);
while(a[--j]>mid);
if(i<j) swap(a[i],a[j]);
}
qsort(l,j);qsort(j+1,r);
}
归并排序,时间——
void msort(int l,int r){
if(l>=r) return ;
int mid=l+r>>1;
msort(l,mid);msort(mid+1,r);
int i=l,j=mid+1,k=1;
while(i<=mid&&j<=r)
if(a[i]<a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(i=l,j=1;i<=r;i++,j++) a[i]=tmp[j];
}
二分,时间——
int l=1,r=n;
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
//尽可能向左找答案
int l=1,r=n;
while(l<r){
int mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
//尽可能向右找答案
double l=1,r=n;
while(l+eps<=r){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
//浮点数二分
高精度
vector<int> add(vector<int> &A,vector<int> &B){
int t=0;vector<int> C;
for(int i=0;i<A.size()||i<B.size();i++){
if(i<A.size()) t+=A[i];
if(i<B.size()) t+=B[i];
C.push_back(t%10);
t/=10;
}
if(t) C.push_back(t);
return C;
}
//高精度加法(高精+高精)
vector<int> sub(vector<int> &A,vector<int> &B){
int t=0;vector<int> C;
for(int i=0;i<A.size();i++){
t=A[i]-t;
if(i<B.size()) t-=B[i];
C.push_back((t+10)%10);
if(t<0) t=1;
else t=0;
}
while(C.size()>1&&!C.back()) C.pop_back();
return C;
}
//高精度减法(高精-高精,A>=B)
vector<int> mul(vector<int> &A,int b){
int t=0;vector<int> C;
for(int i=0;i<A.size();i++){
t+=A[i]*b;
C.push_back(t%10);
t/=10;
}
if(t) C.push_back(t);
return C;
}
//高精度乘法(高精*低精)
vector<int> div(vector<int> &A,int b,int &r){
r=0;vector<int> C;
for(int i=A.size()-1;i>=0;i--){
r=r*10+A[i];
C.push_back(r/b);
r%=b;
}
reverse(C.begin(),C.end());
while(C.size()>1&&!C.back()) C.pop_back();
return C;
}
//高精度除法(高精/高精,带余数)
前缀和,时间——初始化 ,查询
s[i]=s[i-1]+a[i];
以l为左端点,r为右端点的区间的和为:
s[r]-s[l-1];
//一维前缀和
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和为:
s[x2,y2]-s[x1-1,y2]-s[x2,y1-1]+s[x1-1,y1-1];
//二维前缀和
差分,时间——初始化 ,查询
c[i]=a[i]-a[i-1];
给区间[l, r]中的每个数加上x:
c[l]+=x,c[r+1]-=x
//一维差分
c[i][j]=a[i][j];
给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵中的所有元素加上x:
c[x1][y1]+=x,c[x2+1][y1]-=x,c[x1][y2+1]-=x,c[x2+1][y2+1]+=c;
//二维差分
位运算
取出整数 在二进制表示下的第 位:(n>>k)&1
取出整数 在二进制表示下的后 位:n&((1<<k)-1)
把整数 在二进制表示下的第 位取反:n^(1<<k)
把整数 在二进制表示下的第 位赋值 :n|(1<<k)
把整数 在二进制表示下的第 位赋值为 :n&(~(1<<k))
:n&-n
栈,时间——
void push(int x){
stk[++top]=x;
}
//加入元素x
void pop(){
top--;
}
//弹出元素
队列,时间——
void push(int x){
q[++tail]=x;
}
//加入元素x
void pop(){
head++;
}
//弹出元素
大根堆,时间——插入与删除均为
void up(int pos){
while(pos>1){
if(heap[pos]>heap[pos/2]){
swap(heap[pos],heap[pos/2]);
pos/=2;
}
else break;
}
}
//向上调整
void down(int pos){
int s=pos*2;
while(s<=n){
if(s<n&&heap[s]<heap[s+1]) s++;
if(heap[s]>heap[pos]){
swap(heap[s],heap[pos]);
pos=s,s=pos*2;
}
else break;
}
}
//向下调整
void insert(int val){
heap[++n]=val;
up(n);
}
//增加元素
void extract(){
heap[1]=heap[n--];
down(1);
}
//删除堆顶
void remove(int pos){
heap[pos]=heap[n--];
up(pos),down(pos);
}
//删除pos号节点
强连通分量
void Tarjan(int x){
dfn[x]=low[x]=++inx;
stk[++top]=x;vis[x]=1;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(!dfn[y]) Tarjan(y),low[x]=min(low[x],low[y]);
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
ans++;int y=0;
while(x!=y){
y=stk[top--];
vis[y]=0;
belong[y]=ans;
sum[ans]++;
}
}
}
LIS,时间——朴素为 ,优化版为
for(int i=1;i<=n;i++){
f[i]=1;
for(int j=1;j<i;j++){
if(a[j]<a[i]) f[i]=max(f[j]+1,f[i]);
}
ans=max(ans,f[i]);
}
//朴素做法
q[++t]=a[1];
for(int i=2;i<=n;i++){
if(a[i]>q[t]) q[++t]=a[i];
else{
int x=lower_bound(q+1,q+t+1,a[i])-q;
q[x]=a[i];
}
}
//优化版
LCS,时间——朴素为 ,优化版为
for(int i=1;i<=al;i++){
for(int j=1;j<=bl;j++){
if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
}
}
//朴素做法
for(int i=1;i<=n;i++) mp[a[i]]=i;
for(int i=1;i<=n;i++) b[i]=mp[b[i]];
q[++t]=b[1];
for(int i=2;i<=n;i++){
if(b[i]>q[t]) q[++t]=b[i];
else{
int x=lower_bound(q+1,q+t+1,b[i])-q;
q[x]=b[i];
}
}
//优化版
背包
for(int i=1;i<=n;i++){
for(int j=0;j<=v;j++){
if(j>=w[i]) f[i][j]=max(f[i-1][j-w[i]]+val[i],f[i-1][j]);
else f[i][j]=f[i-1][j];
}
}
//朴素做法
for(int i=1;i<=n;i++){
for(int j=v;j>=w[i];j--){
f[j]=max(f[j-w[i]]+val[i],f[j]);
}
}
//优化版
多重背包
for(int i=1;i<=n;i++){
for(int j=0;j<=v;j++){
for(int k=0;k*w[i]<=j&&k<=s[i];k++){
if(j-k*w[i]>=0) f[i][j]=max(f[i-1][j-k*w[i]]+k*val[i],f[i-1][j]);
}
}
}
//朴素做法
for(int k=1;k<=s;k<<=1){
for(int j=v;j>=w*k;j--) f[j]=max(f[j-w*k]+val*k,f[j]);
s-=k;
}
if(s){
for(int j=v;j>=w*s;j--) f[j]=max(f[j-w*s]+val*s,f[j]);
}
//二进制优化
割点
void dfs(int x,int fa){
dfn[x]=low[x]=++inx;
int son=0;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(!dfn[y]){
dfs(y,x);son++;
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]&&x!=root) ans++;
}
else if(y!=fa) low[x]=min(low[x],dfn[y]);
}
if(son>=2&&x==root) if(!cut[x]) ans++;
}
割边
void dfs(int x,int fa){
dfn[x]=low[x]=++inx;
int son=0;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(!dfn[y]){
dfs(y,x);son++;
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x]) ans++;
}
else if(y!=fa) low[x]=min(low[x],dfn[y]);
}
}
算法,时间——朴素为 ,优化版为
void Dijkstra(int x){
for(int i=1;i<=n;i++) d[i]=inf;
d[x]=0;
for(int i=1;i<=n;i++){
int mn=inf,k;
for(int j=1;j<=n;j++){
if(!vis[j]&&mn>d[j]){
mn=d[j];
k=j;
}
}
vis[k]=1;
for(int j=h[k];j;j=e[j].next){
int y=e[j].to;
if(!vis[y]&&d[k]+e[j].data<d[y]){
d[y]=d[k]+e[j].data;
}
}
}
}
//朴素做法
priority_queue<node> q;
void Dijkstra(int x){
for(int i=1;i<=n;i++) d[i]=inf;
d[x]=0;q.push((node){0,v0});
while(q.size()){
int k=q.top().key;
q.pop();
if(vis[k]) continue;
vis[k]=1;
for(int j=h[k];j;j=e[j].next){
int y=e[j].to;
if(!vis[y]&&d[k]+e[j].data<d[y]){
d[y]=d[k]+e[j].data;
q.push((node){d[y],y});
}
}
}
}
//优先队列优化
算法,时间——
bool spfa(int start){
for(int i=1;i<=n;i++) d[i]=inf;
d[start]=0;q.push(start);vis[start]=1;
while(q.size()){
int x=q.front();q.pop();
vis[x]=0;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(d[x]+e[i].data<d[y]){
d[y]=d[x]+e[i].data;
if(!vis[y]){
vis[y]=1;
q.push(y);
sum[y]++;
if(sum[y]>=n) return true;
}
}
}
}
return false;
}
//SPFA判负环
算法,时间——
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
算法,时间——
int find(int x){
if(fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
//查找祖先
for(int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int a=find(e[i].x),b=find(e[i].y);
if(a==b) continue;
fa[a]=b;
cnt++;
ans+=e[i].w;
}
算法,时间——
void Prim(int x){
for(int i=1;i<=n;i++) d[i]=inf;
d[x]=0;
for(int i=1;i<=n;i++){
int mn=inf,k;
for(int j=1;j<=n;j++){
if(!vis[j]&&mn>d[j]) k=j,mn=d[j];
ans+=d[k];vis[k]=1;
for(int j=h[k];j;j=e[j].next){
int y=e[j].to;
if(!vis[y]) d[y]=min(d[y],e[j].data);
}
}
}
}
快速幂,时间——
long long qpow(long long a,long long b{
if(b==0) return 1;
long long ans=qpow(a,b/2);
if(b&1) return ans*ans*a;
else return ans*ans;
}
//递归版
long long qpow(long long a,long long b){
long long ans=1;
while(b>0){
if(b&1) ans*=a;
a*=a;
b>>=1;
}
return ans;
}
//非递归版
线段树,时间——
void build(int key,int l,int r){
tree[key]=(Tree){l,r,0};
if(l==r){
tree[key].sum=a[l];
return ;
}
int mid=l+r>>1;
build(key*2,l,mid);
build(key*2+1,mid+1,r);
tree[key].sum=tree[key*2].sum+tree[key*2+1].sum;
}
//建树
void node_add(int key,int x,int k){
if(tree[key].r<x||tree[key].l>x) return ;
if(tree[key].l==tree[key].r){
tree[key].sum+=k;
return ;
}
int mid=tree[key].l+tree[key].r>>1;
node_add(key*2,x,k);
node_add(key*2+1,x,k);
tree[key].sum=tree[key*2].sum+tree[key*2+1].sum;
}
//单点修改
void inter_ask(int key,int l,int r){
if(tree[key].r<l||tree[key].l>r) return ;
if(tree[key].l>=l&&tree[key].r<=r){
ans+=tree[key].sum;
return ;
}
inter_ask(key*2,l,r);
inter_ask(key*2+1,l,r);
}
//区间询问
欧拉筛,——时间
memset(isprime,1,sizeof(isprime));
isprime[1]=0;
for(int i=2;i<=n;i++){
if(isprime[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
isprime[i*prime[j]]=0;
if(i%prime[j]==0) break;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具