常用模板

这篇博客汇总了多种常用的算法模板,包括双端队列、RMQ线段树、一维树状数组、优先队列、Floyd求点对最短路、旅行商问题等。还提供了线性筛、欧拉函数、大数分解等数论算法的模板,并介绍了迪杰斯特拉算法和最小生成树的实现。对于竞赛编程和算法学习者来说是一份宝贵的参考资料。
摘要由CSDN通过智能技术生成

1、双端队列/单调队列 O(n)

int n,k,a[maxn],b[maxn],deq[maxn];//a[]保存读入的数组;b[]保存一段区间的答案;deq[]双端队列,保存数组下标 
void upper()//值按照升序存放在队列中 
{
	int s=0,t=0;//s:首;t:尾 
	for(int i=0;i<n;i++)
	{
		while(s<t&&a[deq[t-1]]>=a[i]) t--;//进队就保证了顺序,弹出比他大的,进入小的; 
		
		deq[t++]=i;
		if(i-k+1>=0)
		{
			b[i-k+1]=a[deq[s]];//首元素下标用不到就删除 
			if(deq[s]==i-k+1)
			{
				s++;
			}
		}
	}
	for(int i=0;i<(n-k);i++)//输出最终结果 
	{
		printf("%d ",b[i]);
	}
	printf("%d\n",b[n-k]);
}

2、RMQ线段树 O(log(n))

const int M=INTMAX;
int N,dat[2*M-1];//N:树叶个数; 
void init(int m)//线段树初始化 
{
	N=1;
	while(N<m) N*=2;//构建一棵完整的二叉树,树叶为偶数个 
	for(int i=0;i<2*N-1;i++)
	{
		dat[i]=INTMAX;//初始化为最大值 
	}
}

void update(int k,int a)//向上更新节点 
{
	k+=N-1;
	dat[k]=a;
	while(k>0)
	{
		k=(k-1)/2;
		dat[k]=min(dat[k*2+1],dat[k*2+2]);
	}
}

int query(int a,int b, int k,int l,int r)//查询,[a,b):被查询区间;k:节点编号;[l,r):被比较区间 
{                                        //主函数调用时,k=0,l=0,r=N 
	if(r<=a||b<=l) return INTMAX;//区间不相交 
	if(a<=l&&b>=r) return dat[k];//区间全覆盖 
	else//区间有部分交叉,返回左右区间中小的那个值 
	{
		int v1=query(a,b,k*2+1,l,(l+r)/2);
		int v2=query(a,b,k*2+2,(l+r)/2,r);
		return min(v1,v2);
	}

}

3、一维树状数组 (BIT) O(log(n))

int bit[MAXN+1];//树的所有节点 
int sum(int i)//[1,i]区间的和 
{
	int s=0;
	while(i>0)
	{
		s+=bit[i];
		i-=i&(-i); 
	}
	return s;
}

void add(int i,int x)//某个节点增加x,更新全部相关区间直到maxn节点; 
{
	while(i<MAXN)
	{
		bit[i]+=x;
		i+=i&(-i);
	}
}

4、二维树状数组

int bit[MAXN][MAXN];//树状数组大小选取与普通数组一样

int lowbit(int x)
{
	return x&(-x);
}

int sum(int x,int y)
{
	int s=0;
	while(x>0)
	{
		for(int i=y;i>0;i-=lowbit(i))//行与列都是一维BIT,具体分析见之前转载的文章 
		{
			s+=bit[x][i];
		}
		x-=lowbit(x);
	}
	return s;
}

void add(int x,int y,int num)
{
	while(x<MAXN)
	{
		for(int i=y;i<MAXN;i+=lowbit(i))
		{
			bit[x][i]+=num;
		}
		x+=lowbit(x);
	}
}

int query(int x1,int y1,int x2,int y2)
{
	int ans=sum(x2,y2)+sum(x1-1,y1-1)-sum(x1-1,y2)-sum(x2,y1-1);
	return ans;
}

5、线段树区间同加值、求和 O(log(n))

ll N,data[4*maxn],datb[4*maxn];
//开4倍数组,a:data[]:给该点对应的区间内所有元素共同加上的值
//b:datb[]:在该节点对应的区间中除去a以外其他值的和 
void init(int m)
{
	N=1;
	while(N<m) N*=2;
	for(int i=0;i<2*N+1;i++)
	{
		data[i]=0;
		datb[i]=0;
	} 
}

void add(ll a,ll b,ll x,ll k,ll l,ll r)
{
	if(a<=l&&b>=r) data[k]+=x;
	else if(l<b&&a<r)
	{
		datb[k]+=(min(b,r)-max(a,l))*x;
		add(a,b,x,k*2+1,l,(l+r)/2);
		add(a,b,x,k*2+2,(l+r)/2,r);
	}
}

ll sum(ll a,ll b,ll k,ll l,ll r)
{
	if(b<=l||r<=a)
	{
		return 0;
	}
	else if(a<=l&&r<=b)
	{
		return data[k]*(r-l)+datb[k];
	}
	else
	{
		ll res =(min(b,r)-max(a,l))*data[k];
		res+=sum(a,b,k*2+1,l,(l+r)/2);
		res+=sum(a,b,k*2+2,(l+r)/2,r);
		return res;
	}
}

6、线段树区间修改为某值,求和 O(log(n))

int N,_sum;//次模板左闭右闭区间,且下标从1开始;具体见算法竞赛入门经典 
int setv[4*maxn],sumv[4*maxn];
void init(int m)
{
	N=1;
	while(N<m) N*=2;
	for(int i=1;i<2*N+1;i++)
	{
		setv[i]=0;//初始标记根据题目数字来改动 
		sumv[i]=0;
	}
}

void maintain(int o,int a,int b)
{
	
	int lc=o*2;
	int rc=o*2+1;
	sumv[o]=0;
	if(setv[o]>0)
	{
		sumv[o]=setv[o]*(b-a+1);
	}
	else if(b>a) sumv[o]=sumv[lc]+sumv[rc];
}

void pushdown(int o)
{
	int lc=o*2;
	int rc=o*2+1;
	if(setv[o]>0)
	{
		setv[lc]=setv[rc]=setv[o];
		setv[o]=0;
	}
}

void update(int a,int b,int v,int o,int l, int r)
{
	int lc=o*2;
	int rc=o*2+1;
	if(a<=l&&b>=r)
	{
		setv[o]=v;
	}
	else
	{
		pushdown(o);
		int M=(r+l)/2;
		if(a<=M) update(a,b,v,lc,l,M);
		else maintain(lc,l,M);
		if(b>M) update(a,b,v,rc,M+1,r);
		else maintain(rc,M+1,r);		
	}
	maintain(o,l,r);
}

void query(int a,int b,int o,int l,int r)
{
	if(setv[o]>0)
	{
		_sum+=setv[o]*(min(b,r)-max(l,a)+1);
	}
	else if(a<=l&&b>=r)
	{
		_sum+=sumv[o];
	}
	else
	{
		int M=(r+l)/2;
		if(a<=M) query(a,b,o*2,l,M);
		if(b>M) query(a,b,o*2+1,M+1,r);
	}
}

另见:https://www.cnblogs.com/Kiraa/p/6046208.html(感谢!)

           https://blog.csdn.net/Fire_to_cheat_/article/details/80713972

7、优先队列

# include<queue>
struct node
{
	int h;
	int st;
	friend bool operator < (node a,node b)
	{
		return a.st>b.st;//它也是按照重载后的小于规则,从大到小排序的。入队后自动排序 
	}
};

priority_queue<node> Q;
Q.push();
Q.top();
Q.pop();

8.1、凸包算法(O(nlogn))

struct node
{
	ll x,y;
};
node n[maxn],
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值