常用模版(征集中)4

本文展示了多种算法的实现,包括基于模逆运算的线性递推求逆元,组合数的计算,字典树的构建和查询,可持久化线段树的插入和查询操作,单调队列的应用,以及长链剖分LCA和Splay树的数据结构操作。这些算法在解决计算和数据组织问题时具有重要作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线性递推求逆元

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e6+1;
int n;
ll p,inv[N];
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>p;
	inv[1]=1;
/*
	设 	t=p/i k=p%i
	则 	p=ti+k
	下面用'='表示同余 
		0=ti+k (mod p)
	   -k=ti   (mod p)
	这里的除号表示乘以它的逆元 
	-k/ki=ti/ki(mod p)
	  1/i=-t/k (mod p)
	即inv[i]=-(p/i)*inv[p%i] (mod p)
	即inv[i]=(p-(p/i)*inv[p%i]%p)%p; 
*/
	for(int i=2;i<=n;i++) inv[i]=(p-(p/i)*inv[p%i]%p)%p;
	for(int i=1;i<=n;i++) cout<<inv[i]<<"\n";
	return 0;
}

组合数求解

const int N=1e6+1,V=1e6;
const ll R=1e8+7;
int T,n,m;
ll fac[N],inv[N];
inline ll power(ll a,ll b){
	ll ans=1;
	for(;b;b>>=1){
		if(b&1) (ans*=a)%=R;
		(a*=a)%=R;
	}
	return ans;
}
void init(){
	fac[0]=inv[0]=1;
	for(int i=1;i<=V;i++) fac[i]=(fac[i-1]*i)%R;
	inv[V]=power(fac[V],R-2);
	for(int i=V-1;i>=1;i--) inv[i]=(inv[i+1]*(i+1))%R;
}
inline ll C(int x,int y){
	if(x<y) return 0;
	return (1ll*fac[x]*inv[y]%R*inv[x-y]+R)%R;
}

字典树

int t[N][27],len,n,m,tot[N],cnt;
char s[N];
inline void insrt(){
	int p=0;
	len=strlen(s+1);
	for(int i=1;i<=len;i++){
		int c=s[i]-'a'+1;
		if(!t[p][c]) t[p][c]=++cnt;
		p=t[p][c];
	}
	tot[p]++;
}
inline int check(){
	int p=0,ans=0;
	len=strlen(s+1);
	for(int i=1;i<=len;i++){
		int c=s[i]-'a'+1;
		p=t[p][c];
		if(!p) break;
		ans+=tot[p];
	}
	return ans;
}

可持久化线段树

 

int build(int l,int r){
	int p=++tot;
	if(l==r) return p;
	int mid=(l+r)/2;
	tree[p].l=build(l,mid);
	tree[p].r=build(mid+1,r);
}
int insert(int p,int l,int r,int x){
	int q=++tot;
	tree[q]=tree[p];
	if(l==r){
		tree[q].data++;
		return q;
	}
	int mid=(l+r)/2;
	if(x<=mid) tree[q].l=insert(tree[p].l,l,mid,x);
	else if(x>mid) tree[q].r=insert(tree[p].r,mid+1,r,x);
	tree[q].data=tree[tree[q].l].data+tree[tree[q].r].data;
	return q;
}

单调队列

#include<bits/stdc++.h>
#define size (r-l+1)
#define dpos (q[r].pos-q[l].pos+1)
using namespace std;
const int N=1e6+1;
int n,k,a[N],l,r;
struct Node{
	int val,pos;
}q[N];
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	l=1,r=0;
	for(int i=1;i<=n;i++){
		while(size&&q[r].val>=a[i]) r--;
		r++;
		q[r].val=a[i],q[r].pos=i;
		while(dpos>k) l++;
		if(i>=k) cout<<q[l].val<<" ";
	}
	cout<<"\n";
	l=1,r=0;
	for(int i=1;i<=n;i++){
		while(size&&q[r].val<=a[i]) r--;
		r++;
		q[r].val=a[i],q[r].pos=i;
		while(dpos>k) l++;
		if(i>=k) cout<<q[l].val<<" ";
	}
	return 0;
}

长链剖分lca

void dfs1(int cur,int last){
	fa[cur]=last;
	depthmax[cur]=depth[cur]=depth[last]+1;
	for(int i=head[cur];i;i=edge[i].nxt){
		int ver=edge[i].to;
		if(ver==last) continue;
		dfs1(ver,cur);
		if(depthmax[ver]>depthmax[cur]) son[cur]=ver,depthmax[cur]=depthmax[ver];
	}
}
void dfs2(int cur,int topf){
	top[cur]=topf;
	if(!son[cur]) return;
	dfs2(son[cur],topf);
	for(int i=head[cur];i;i=edge[i].nxt){
		int ver=edge[i].to;
		if(ver==fa[cur]||ver==son[cur]) continue;
		dfs2(ver,ver);
	}
}
int query(int x,int y){
	while(top[x]!=top[y]){
		if(depth[top[x]]<depth[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(depth[x]<depth[y]) return x;
	else return y;
}

splay

​
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5;
int sz[N],cnt[N],fa[N],son[N][2],val[N],rt=0,tot=0;
void geng(int x){sz[x]=sz[son[x][0]]+sz[son[x][1]]+cnt[x];}
void lian(int x,int f,int u){fa[x]=f,son[f][u]=x;}
bool getson(int x){return son[fa[x]][1]==x;}
void zhuan(int x){
	int y=fa[x],z=fa[y],u=getson(x),v=getson(y);
	lian(x,z,v),lian(son[x][u^1],y,u),lian(y,x,u^1);
	geng(y),geng(x);
}
void splay(int x){
	for(int f=fa[x];f;zhuan(x),f=fa[x])
		if(fa[f])zhuan(getson(x)==getson(f)?f:x);
	rt=x;
}
void jia(int &x,int k,int f){
	if(!x){
		x=++tot,sz[tot]=cnt[tot]=1,val[tot]=k,fa[tot]=f,son[tot][0]=son[tot][1]=0;
		return splay(x);
	}
	sz[x]++;
	if(k==val[x])cnt[x]++;
	else if(k>val[x])jia(son[x][1],k,x);
	else jia(son[x][0],k,x);
}
int pai1(int x,int k){
	if(k==val[x]){splay(x);return sz[son[x][0]]+1;}
	if(k>val[x])return pai1(son[x][1],k);
	return pai1(son[x][0],k);
}
int pai2(int x,int k){
	if(sz[son[x][0]]>=k)return pai2(son[x][0],k);
	k-=(sz[son[x][0]]+cnt[x]);
	if(k<=0){splay(x);return val[x];}
	else return pai2(son[x][1],k);
}
int qian(int k){
	int x=rt,ans;
	while(x){
		if(k>val[x])ans=x,x=son[x][1];
		else x=son[x][0];
	}
	return val[ans];
}
int hou(int k){
	int x=rt,ans;
	while(x){
		if(k<val[x])ans=x,x=son[x][0];
		else x=son[x][1];
	}
	return val[ans];
}
void shan(int k){
	pai1(rt,k);
	if(--cnt[rt])return;
	if(!son[rt][0]&&!son[rt][1])rt=0;
	else if(!son[rt][0])rt=son[rt][1],fa[rt]=0,geng(rt);
	else if(!son[rt][1])rt=son[rt][0],fa[rt]=0,geng(rt);
	else{
		int k=rt,tmp=son[rt][0];
		while(son[tmp][1])tmp=son[tmp][1];
		splay(tmp),fa[son[k][1]]=rt,son[rt][1]=son[k][1],geng(rt);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n,op,x;
	cin>>n;
	while(n--){
		cin>>op>>x;
		switch(op){
			case 1:jia(rt,x,0);break;//插入x数;
			case 2:shan(x);break;//删除x数;
			case 3:cout<<pai1(rt,x)<<'\n';break;//查询x数的排名(若有多个相同的数,因输出最小的排名);
			case 4:cout<<pai2(rt,x)<<'\n';break;//查询排名为x的数;
			case 5:cout<<qian(x)<<'\n';break;//求x的前趋(前趋定义为小于x,且最大的数);
			case 6:cout<<hou(x)<<'\n';break;//求x的后继(后继定义为大于x,且最小的数)。
		}
	}
	return 0;
}

​

三分模板

while(l+eps<r){
		lmid=l+(r-l)/3;
		rmid=r-(r-l)/3;
		if(calc(lmid)<calc(rmid)) r=rmid;
		else l=lmid;
	}

树上启发式合并 dsu on tree

#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N=1e5+1,M=2e5+1;
int n,m,f[N],sz[N],son[N];
int tot,head[N],ver[M],nxt[M];
int c[N],ans[N];
struct Node{//离散化数组 
	int val,pos;
}a[N];
inline bool cmpval(Node A,Node B){
	return A.val<B.val;
}
inline bool cmppos(Node A,Node B){
	return A.pos<B.pos;
}
inline void addedge(int x,int y){//加边 
	tot++;
	ver[tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void compress(){//离散化 
	sort(a+1,a+n+1,cmpval);
	for(int i=1;i<=n;i++){
		if(a[i+1].val!=a[i].val) m++;
		a[i].val=m;
	}
	sort(a+1,a+n+1,cmppos);
}
inline void dfs(int x){//找到重儿子 
	sz[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		dfs(y);
		sz[x]+=sz[y];
		if(sz[y]>sz[son[x]]) son[x]=y;
	}
}
inline void add(int x,int y){//树状数组...这道题需要使用,普通的dsu维护桶 
	for(;x<=m;x+=lowbit(x)) c[x]+=y;
}
inline int ask(int x){
	int sum=0;
	for(;x;x-=lowbit(x)) sum+=c[x];
	return sum;
}
inline void add(int x){
	add(a[x].val,1);
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		add(y);
	}
}
inline void del(int x){
	add(a[x].val,-1);
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		del(y);
	}
}
inline void solve(int x){
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==son[x]) continue;
		solve(y);//走轻儿子 
		del(y);//删轻儿子 
	}
	if(son[x]) solve(son[x]);//走重儿子 
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==son[x]) continue;
		add(y);//加轻儿子 
	}
	add(a[x].val,1);//加自己 
	ans[x]=sz[x]-ask(a[x].val);//统计答案 
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].val;
		a[i].pos=i;
	}
	for(int i=2;i<=n;i++){
		cin>>f[i];
		addedge(f[i],i);
	}
	compress(); 
	dfs(1);
	solve(1);
	for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
	return 0;
}

快速乘

inline int(int a,int b,int p)
{
    int s=0;
    while(b)
    {
        if(b&1)s=s+a%p;
        a=a+a%p;
        b>>=1;
    }
    return s;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值