省选模板
-
各种平衡树
-
(可并)堆
-
各种莫队
-
各种可持久化
-
线段树合并、分裂、分治
-
LCT
-
tarjan 缩强连通分量
Graph G;
int dfn[N],low[N],dfscnt;
int stack[N],top;
int scc[N],scccnt;
void tarjan(int u){
dfn[u]=low[u]=++dfscnt;stack[top++]=u;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!dfn[v]){
tarjan(v);
low[u]=std::min(low[u],low[v]);
}
else if(!scc[v]) low[u]=std::min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scccnt++;
do{
scc[stack[--top]]=scccnt;
}while(stack[top]^u);
}
}
- tarjan 求割点
Graph G;
int dfn[N],low[N],dfscnt;
int cut[N];
void tarjan(int u,int root){
dfn[u]=low[u]=++dfscnt;
int cnt=0;
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!dfn[v]){
tarjan(v,root);
low[u]=std::min(low[v],low[u]);
if(low[v]>=dfn[u]&&u!=root) cut[u]=1;
cnt++;
}
low[u]=std::min(low[u],dfn[v]);
}
if(cnt>1&&u==root) cut[u]=1;
}
- 最大流
#define Type int
#define _INF _INT_INF
struct Graph{
int fir[N],_fir[N],nex[M],to[M],tot;
Type w[M];
inline void add(int u,int v,Type c,int flag=1){
to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;w[tot]=c;
if(flag) add(v,u,0,0);
}
}G;
int n,S,T;
int deep[N];
int left,right,que[N];
inline int bfs(){
__builtin_memset(deep,0,(n+1)*sizeof deep[0]);
left=right=0;que[0]=S;deep[S]=1;
int u;
while(left<=right){
u=que[left++];
for(int v,i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(deep[v]||!G.w[i]) continue;
deep[v]=deep[u]+1;que[++right]=v;
if(v==T) return 1;
}
}
return 0;
}
Type dfs(int u,Type now=_INF){
if(u==T) return now;
Type res=now;
for(int v,&i=G._fir[u];i;i=G.nex[i]){
v=G.to[i];
if(deep[v]!=deep[u]+1||!G.w[i]) continue;
Type k=dfs(v,lib::min(res,G.w[i]));
if(!k) deep[v]=0;
else G.w[i]-=k,G.w[i^1]+=k,res-=k;
if(!res) break;
}
return now-res;
}
inline Type dinic(){
Type ans=0;
while(bfs()){
Type now;
__builtin_memcpy(G._fir,G.fir,(n+1)*sizeof G.fir[0]);
while(now=dfs(S)) ans+=now;
}
return ans;
}
- 费用流
#define Type int
#define _INF _INT_INF
int n,m,S,T;
Graph G;
Type mincost,maxflow,h[N];
int vis[N];
inline void spfa(){
static int que[M*10],left,right;
__builtin_memset(h,0x3f,sizeof h);
h[S]=0;vis[S]=1;
left=0;right=-1;que[++right]=S;
int u,i,v;
while(left<=right){
u=que[left++];vis[u]=0;
for(i=G.fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!G.w[i]||h[v]<=h[u]+G.c[i]) continue;
h[v]=h[u]+G.c[i];
if(!vis[v]) que[++right]=v,vis[v]=1;
}
}
}
Type dfs(int u,Type want=_INF){
if(u==T) return mincost+=(h[S]-h[T])*want,maxflow+=want,want;
vis[u]=1;
Type last=want;
for(int v,&i=G._fir[u];i;i=G.nex[i]){
v=G.to[i];
if(!G.w[i]||vis[v]||G.c[i]!=h[u]-h[v]) continue;
Type k=dfs(v,std::min(last,G.w[i]));
G.w[i]-=k;G.w[i^1]+=k;last-=k;
if(!last) break;
}
return want-last;
}
inline int relable(){
Type d=_INF;
for(int i=1;i<=n;i++)if(vis[i])
for(int j=G.fir[i];j;j=G.nex[j])if(G.w[j]&&!vis[G.to[j]]) d=std::min(d,G.c[j]-h[i]+h[G.to[j]]);
if(d==_INF) return 0;
for(int i=1;i<=n;i++)if(vis[i]) h[i]+=d;
return 1;
}
inline void zkw(){
spfa();
do{
do{
__builtin_memset(vis,0,sizeof vis);__builtin_memcpy(G._fir,G.fir,sizeof G._fir);
}while(dfs(S));
}while(relable());
}
-
点分治(点分树)
-
支配树
Graph G,H,T;
int dfscnt,dfn[N],id[N],fa[N];
int idom[N],sdom[N];
struct UnionSet{
int fa[N],min[N];
inline int find(int k){
if(fa[k]==k) return k;
int father=find(fa[k]);
if(dfn[sdom[min[fa[k]]]]<dfn[sdom[min[k]]]) min[k]=min[fa[k]];
return fa[k]=father;
}
}S;
void dfs(int u){
dfn[u]=++dfscnt;id[dfscnt]=u;
for(int i=G.fir[u];i;i=G.nex[i])if(!dfn[G.to[i]]) fa[G.to[i]]=u,dfs(G.to[i]);
}
inline void build(int root){
dfs(root);
for(int i=1;i<=dfscnt;i++) sdom[i]=S.fa[i]=S.min[i]=i;
for(int u,i=dfscnt;i>1;i--){
u=id[i];
for(int v,j=T.fir[u];j;j=T.nex[j])if(dfn[T.to[j]]){
v=T.to[j];S.find(v);
if(dfn[sdom[S.min[v]]]<dfn[sdom[u]]) sdom[u]=sdom[S.min[v]];
}
S.fa[u]=fa[u];
H.add(sdom[u],u);u=fa[u];
for(int v,j=H.fir[u];j;j=H.nex[j]){
v=H.to[j];S.find(v);
idom[v]=(u==sdom[S.min[v]])?u:S.min[v];
}
H.fir[u]=0;
}
for(int u,i=2;i<=dfscnt;i++){
u=id[i];
if(idom[u]^sdom[u]) idom[u]=idom[idom[u]];
}
}
-
2-SAT,差分约束
-
LGV 引理
-
矩阵树定理,BEST 定理
-
图匹配
-
最小树形图
-
原根
-
长链剖分
-
高斯消元
需要求逆元:
inline ModInt det(int n,ModInt (*a)[N]){
ModInt ans;ans=1;
for(int i=1;i<=n;i++){
if(!a[i][i].x){
ans=0-ans;
for(int k=i+1;k<=n;k++)if(a[k][i].x){std::swap(a[i],a[k]);goto CONTINUE;}
return {0};
}
CONTINUE:
ans*=a[i][i];
for(int k=i+1;k<=n;k++)if(a[k][i].x){
ModInt o=a[k][i]/a[i][i];
for(int j=i;j<=n;j++) a[k][j]-=a[i][j]*o;
}
}
return ans;
}
不需要逆元:
inline ModInt det(){
ModInt ans;ans=1;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
while(a[j][i]){
long long k=a[i][i]/a[j][i];
for(int h=1;h<=n;h++) a[i][h]-=k*a[j][h];
std::swap(a[i],a[j]);
ans=-ans;
}
}
}
for(int i=1;i<=n;i++) ans*=a[i][i];
return ans;
}
-
manacher, kmp
-
AC 自动机
struct Node{
Node *son[26],*fail;
int cnt;
}addr[N],*root=addr,*tot=root+1;
inline void insert(char *s){
Node *tree=root;
for(int num,i=1;s[i];i++){
num=s[i]-'a';
if(!tree->son[num]) tree->son[num]=tot++;
tree=tree->son[num];tree->cnt++;
}
}
inline void build(){
static Node *que[N];int left=0,right=-1;
root->fail=root;
for(int i=0;i<26;i++){
if(root->son[i]) root->son[i]->fail=root,que[++right]=root->son[i];
else root->son[i]=root;
}
Node *u;
while(left<=right){
u=que[left++];
for(int i=0;i<26;i++){
if(u->son[i]){
u->son[i]->fail=u->fail->son[i];
que[++right]=u->son[i];
}
else u->son[i]=u->fail->son[i];
}
}
}
-
PAM
-
SAM
struct Node{
Node *son[26];
int len,cnt;
Node *link;
}dizhi[N*2],*root=&dizhi[0],*last=root;
int tot;
inline void add(int c){
Node *p=last,*now=&dizhi[++tot];
now->len=p->len+1;now->cnt=1;
for(;p&&!p->son[c];p=p->link) p->son[c]=now;
if(!p) now->link=root;
else{
Node *q=p->son[c];
if(q->len==p->len+1) now->link=q;
else{
Node *clone=&dizhi[++tot];*clone=*q;
clone->len=p->len+1;clone->cnt=0;
q->link=now->link=clone;
for(;p&&p->son[c]==q;p=p->link) p->son[c]=clone;
}
}
last=now;
}
-
crt,Lucas 定理,(扩展)欧拉定理,(扩展)BSGS
-
各种筛法
-
FWT
inline void Or(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j+h]+=f[i+j];}
inline void IOr(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j+h]-=f[i+j];}
inline void And(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j]+=f[i+j+h];}
inline void IAnd(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j]-=f[i+j+h];}
inline void Xor(int n,long long *f){
for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++)
f[i+j]+=f[i+j+h],f[i+j+h]=f[i+j]-f[i+j+h]-f[i+j+h];
}
inline void IXor(int n,long long *f){
for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++)
f[i+j]+=f[i+j+h],f[i+j+h]=f[i+j]-f[i+j+h]-f[i+j+h],f[i+j]*=inv2,f[i+j+h]*=inv2;
}
-
线性基
-
辛普森积分