OI模板(持续更新)

快速排序,时间—— O(nlogn)

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);
}

归并排序,时间—— O(nlogn)

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];
}

二分,时间—— O(logn)

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;
}
//高精度除法(高精/高精,带余数)

前缀和,时间——初始化 O(n) ,查询 O(1)

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];
//二维前缀和

差分,时间——初始化 O(n) ,查询 O(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 位:(n>>k)&1

取出整数 n 在二进制表示下的后 k 位:n&((1<<k)-1)

把整数 n 在二进制表示下的第 k 位取反:n^(1<<k)

把整数 n 在二进制表示下的第 k 位赋值 1n|(1<<k)

把整数 n 在二进制表示下的第 k 位赋值为 0n&(~(1<<k))

lowbit(n)n&-n


栈,时间—— O(1)

void push(int x){
	stk[++top]=x;
}
//加入元素x
void pop(){
	top--;
}
//弹出元素

队列,时间—— O(1)

void push(int x){
	q[++tail]=x;
}
//加入元素x
void pop(){
	head++;
}
//弹出元素

大根堆,时间——插入与删除均为 O(logn)

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,时间——朴素为 O(n2) ,优化版为 O(nlogn)

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,时间——朴素为 O(n2) ,优化版为 O(nlogn)

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];
	}
}
//优化版

01 背包

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]);
	}
}

Dijkstra 算法,时间——朴素为 O(n2) ,优化版为 O(nlogn)

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});	
			}
		}
	}
}
//优先队列优化

SPFA 算法,时间—— O(km)

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判负环

Floyd 算法,时间—— O(n3)

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]);
		}
	}
}

Krustal 算法,时间—— O(nlogn)

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;
}

Prim 算法,时间—— O(n2)

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);
			}
		}
	}
}

快速幂,时间—— O(logn)

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;
}
//非递归版

线段树,时间—— O(2logn)

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);
}
//区间询问

欧拉筛,——时间 O(n)

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;
	}
}
posted @   HEIMOFA  阅读(131)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示