考前扫盲 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
-
消去其他行主元
点击查看代码
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
- 缩点(有向图)
点击查看代码
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;
}
}
}
- 割点
注意根要连接至少两个连通块才算
点击查看代码
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;
}
- 边双
两个边双之间的就是桥
点击查看代码
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);
}
}
}
- 点双
点击查看代码
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;
}

浙公网安备 33010602011771号