考前扫盲 2025

1. exgcd

点击查看代码
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	ll d=exgcd(b,a%b,x,y);
	ll t=x;
	x=y;
	y=t-(a/b)*y;
	return d;
}

特解:\(x_0=x*\frac{c}{d},y_0=y*\frac{c}{d}\)

通解:\(x=x_0+t*\frac{b}{d},y=y_0+t*\frac{a}{d}\)

最小正整数:记 \(tx=\frac{b}{d},k=\lceil\frac{1-x_0}{tx}\rceil\)

\(x_{min}=x_0+k*tx,y_{max}=y_0-k*ty\)

2. crt

由余数可加性得到类似如下方程组:

\[\begin{cases}x1\equiv a1 \bmod b1 \\ x1\equiv 0 \bmod b2\\ \dots \\ x1\equiv 0 \bmod bn\end{cases} \]

\(x=\sum_{i=1}^n x_i\)

然后对每个分别求解

先将 x 记作 \(y*a_i\)

可以发现每个 y 必然是另外 n-1 个 b 乘积的倍数,记作 \(m\),则有 \(y=mk\)

所以 \(mk+b_ip=1\)

由互质,可以 exgcd

3. 高斯消元

步骤:

  1. 找到主元为 1 的行,交换

  2. 主元系数化为 1

  3. 消去其他行主元

点击查看代码
void guass()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<=n;j++)
		{
			if(fabs(a[j][i])>eps)
			{
				swap(a[i],a[j]);
				break;
			}
		}
		if(fabs(a[i][i])<eps)
		{
			printf("No Solution");
			return;
		}
		for(int j=n+1;j>=i;j--)
		{
			a[i][j]/=a[i][i];
		}
		for(int j=i+1;j<=n;j++)
		{
			for(int k=n+1;k>=i;k--)
			{
				a[j][k]-=a[j][i]*a[i][k];
			}
		}
	}
	for(int i=n-1;i>0;i--)
	{
		for(int j=i+1;j<=n;j++)
		{
			a[i][n+1]-=a[i][j]*a[j][n+1];
		}
	}
	for(int i=1;i<=n;i++)
	{
		printf("%.2lf\n",a[i][n+1]);
	}
}

4. tarjan

  1. 缩点(有向图)
点击查看代码
void tarjan(int u)
{
	dfn[u]=low[u]=++idx;
	st[++top]=u;
	ins[u]=1;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(ins[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		scc++;
		int v=0;
		while(v!=u)
		{
			v=st[top--];
			id[v]=scc;
			ins[v]=0;
		}
	}
}
  1. 割点

注意根要连接至少两个连通块才算

点击查看代码
void tarjan(int u,int rt)
{
	int child=0;
	dfn[u]=low[u]=++idx;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			tarjan(v,rt);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&u!=rt) cut[u]=1;
			else if(u==rt) child++;
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(u==rt&&child>1) cut[u]=1;
}
  1. 边双

两个边双之间的就是桥

点击查看代码
void tarjan(int u,int in_edge)
{
	dfn[u]=low[u]=++idx;
	st[++top]=u;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			tarjan(v,i);
			low[u]=min(low[u],low[v]);
		}
		else if(i!=(in_edge^1)) 
		{
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u])
	{
		int v=0;
		dcc++;
		while(v!=u)
		{
			v=st[top--];
			ve[dcc].push_back(v);
		}
	}
}
  1. 点双
点击查看代码
void tarjan(int u)
{
	dfn[u]=low[u]=++idx;
	st[++top]=u;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
				int x=0;
				dcc++;
				while(x!=v)
				{
					x=st[top--];
					ve[dcc].push_back(x);
				}
				ve[dcc].push_back(u);
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

树剖

求 lca

点击查看代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e5+5;
int n,m,s,edgenum,head[N];
struct edge{
	int to,nxt;
}e[N*2];
void add_edge(int u,int v)
{
	e[++edgenum].nxt=head[u];
	e[edgenum].to=v;
	head[u]=edgenum;
}
int siz[N],top[N],dep[N],son[N],f[N];
void dfs(int u,int fa)
{
	siz[u]=1,dep[u]=dep[fa]+1,f[u]=fa;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs1(int u,int tp)
{
	top[u]=tp;
	if(son[u])
	{
		dfs1(son[u],tp);
	}
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f[u]||v==son[u]) continue;
		dfs1(v,v);
	}
}
int getlca(int u,int v)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=f[top[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	return u;
}
int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add_edge(u,v),add_edge(v,u);
	}
	dfs(s,0);
	dfs1(s,0);
	while(m--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",getlca(x,y));
	}
	return 0;
}

treap

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,idx,rt;
struct treap{
	int l,r,val,siz,rnd;
}tr[N];
void newnode(int &x,int y)
{
	x=++idx;
	tr[x].siz=1,tr[x].val=y,tr[x].rnd=rand();
}
void pushup(int x)
{
	tr[x].siz=tr[tr[x].l].siz+tr[tr[x].r].siz+1;
}
void split(int p,int v,int &x,int &y)
{
	if(!p)
	{
		x=y=0;
		return;
	}
	if(tr[p].val<=v)
	{
		x=p;
		split(tr[p].r,v,tr[x].r,y);
		pushup(x);
	}
	else
	{
		y=p;
		split(tr[p].l,v,x,tr[y].l);
		pushup(y);
	}
}
int merge(int x,int y)
{
	if(!x||!y) return x+y;
	if(tr[x].rnd<tr[y].rnd)
	{
		tr[x].r=merge(tr[x].r,y);
		pushup(x);
		return x;
	}
	else
	{
		tr[y].l=merge(x,tr[y].l);
		pushup(y);
		return y;
	}
}
void insert(int v)
{
	int x,y,z;
	newnode(x,v);
	split(rt,v-1,z,y);
	rt=merge(merge(z,x),y);
}
void del(int v)
{
	int x,y,z;
	split(rt,v-1,z,x);
	split(x,v,x,y);
	x=merge(tr[x].l,tr[x].r);
	rt=merge(merge(z,x),y);
}
int getrnk(int v)
{
	int y,x,s;
	split(rt,v-1,y,x);
	s=tr[y].siz+1;
	rt=merge(y,x);
	return s;
}
int getval(int p,int k)
{
	if(k==tr[tr[p].l].siz+1) return tr[p].val;
	if(k<=tr[tr[p].l].siz) return getval(tr[p].l,k);
	else return getval(tr[p].r,k-tr[tr[p].l].siz-1);
}
int getpre(int v)
{
	int x=getrnk(v);
	return getval(rt,x-1);
}
int getnxt(int v)
{
	int x=getrnk(v+1);
//	printf("%d ",x);
	return getval(rt,x);
}
int main()
{
	srand((unsigned)time(0));
	scanf("%d",&n);
	while(n--)
	{
		int opt,x;
		scanf("%d%d",&opt,&x);
		if(opt==1) insert(x);
		if(opt==2) del(x);
		if(opt==3) printf("%d\n",getrnk(x));
		if(opt==4) printf("%d\n",getval(rt,x));
		if(opt==5) printf("%d\n",getpre(x));
		if(opt==6) printf("%d\n",getnxt(x));
	}
	return 0;
}
posted @ 2025-10-31 10:02  wangsiqi2010916  阅读(10)  评论(0)    收藏  举报