常用模板
本文为我在 OI 中的常用模板。
参考资料
通用
文件
联赛文件模板:name.zip
框架
- 基础框架
- 快捷框架 1
- 快捷框架 2
#include <bits/stdc++.h>
using namespace std;
int main()
{
return 0;
}
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=100005;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const int N=100005;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}
性能
#include <bits/stdc++.h>
using namespace std;
using namespace chrono;
int main()
{
auto st=high_resolution_clock::now();
/* code */
auto ed=high_resolution_clock::now();
cout<<duration_cast<microseconds>(ed-st).count()<<'\n';
return 0;
}
读写
详见 读写优化。
关闭同步 & 解除关联
ios::sync_with_stdio(false);
cin.tie(nullptr);
快读快写
- getchar
- getchar_unlocked
- namespace IO
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=x*10+c-48,c=getchar();
return x*f;
}
void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
}
int read()
{
int x=0,f=1;char c=getchar_unlocked();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar_unlocked();}
while(c>='0'&&c<='9')x=x*10+c-48,c=getchar_unlocked();
return x*f;
}
void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
}
namespace IO
{
#define MAX_SIZE (1<<16)
char buf[MAX_SIZE],pbuf[MAX_SIZE],*p1,*p2,*pp=pbuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAX_SIZE,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (pp==pbuf+MAX_SIZE&&(fwrite(pbuf,1,MAX_SIZE,stdout),pp=pbuf),*pp++=(x))
#define flush() (fwrite(pbuf,1,pp-pbuf,stdout),pp=pbuf)
inline char read(char &x){while(x=getchar(),isspace(x));return x;}
inline void print(const char x){putchar(x);}
inline char* read(char *x){static char ch;while(ch=getchar(),isspace(ch));while(~ch&&!isspace(ch)) *x++=ch,ch=getchar();*x='\000';return x;}
inline void print(char *x){while(*x) putchar(*x++);}inline void print(const char *x){while(*x) putchar(*x++);}
template<typename T> inline T read(T &x){static char ch;bool f=true;x=0;while(ch=getchar(),(~ch&&!isdigit(ch))) f&=(bool)(ch^'-');while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return x=f?x:-x;}
template<typename T> inline void print(T x){static short stk[20],top=0;if(x<0) x=-x,putchar('-');do stk[top++]=x%10,x/=10;while(x);while(top) putchar(stk[--top]^48);}
template<typename T,typename ...T1>inline T read(T &a,T1 &...b){return read(a),read(b...),a;}
template<typename T,typename ...T1>inline void print(const T a,const T1 ...b){print(a);print(b...);}
struct in{}cin;struct out{~out(){flush();}}cout;
inline in& operator>>(in &io,char *x){return read(x),io;}
template<typename T> inline in& operator>>(in &io,T &x){return read(x),io;}
template<typename T> inline out& operator<<(out &io,const T x){return print(x),io;}
}
文件读写
freopen("problem.in","r",stdin);
freopen("problem.out","w",stdout);
cout 格式化
cout<<fixed<<setprecision(6)<<x<<'\n';
cout<<setfill('0')<<setw(6)<<x<<'\n';
刷新缓冲区
cout<<flush;
fflush(stdout);
cout.flush();
算法基础
排序
详见 排序。
void msort(int l,int r)
{
if(l==r)return;
msort(l,mid);
msort(mid+1,r);
int p1=l,p2=mid+1;
for(int i=l;i<=r;i++)
{
bool t=p1<=mid&&(p2>r||a[p1]<=a[p2]);
b[i]=t?a[p1++]:a[p2++];
}
for(int i=l;i<=r;i++)a[i]=b[i];
}
二分
详见 二分。
- 整数
- 实数
int l=x,r=y+1;
while(l<r)
{
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
double l=x,r=y;
while(r-l>eps)
{
double mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
字符串
KMP 算法
详见 字符串匹配。
int kmp(string s,string t)
{
int n=s.size(),m=t.size();
for(int i=1;i<m;i++)
{
int j=nxt[i-1];
while(j&&t[i]!=t[j])j=nxt[j-1];
if(t[i]==t[j])j++;
nxt[i]=j;
}
int j=0;
for(int i=0;i<n;i++)
{
while(j&&s[i]!=t[j])j=nxt[j-1];
if(s[i]==t[j])j++;
if(j==m)return i-m+1;
}
return -1;
}
字典树
详见 字典树。
struct Trie
{
int T[N][M],val[N];
int cnt=0;
void init()
{
for(int i=0;i<=cnt;i++)
{
memset(T[i],0,sizeof T[i]);
val[i]=0;
}
cnt=0;
}
void insert(string s)
{
int u=0;
for(auto c:s)
{
int &v=T[u][c];
if(!v)v=++cnt;
val[u=v]++;
}
}
int query(string s)
{
int u=0;
for(auto c:s)
{
int v=T[u][c];
if(!v)return 0;
u=v;
}
return val[u];
}
};
数学
快速幂
详见 快速幂。
ll Pow(ll x,ll y)
{
x%=mod;
ll res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
排列组合
详见 排列组合。
ll inv[N],fac[N],jv[N];
void init()
{
fac[0]=jv[0]=1;
for(int i=1;i<N;i++)
{
inv[i]=i==1?1:(mod-mod/i)*inv[mod%i]%mod;
fac[i]=fac[i-1]*i%mod;
jv[i]=jv[i-1]*inv[i]%mod;
}
}
ll C(ll n,ll m)
{
if(n<m||m<0)return 0;
return fac[n]*jv[n-m]%mod*jv[m]%mod;
}
ll A(ll n,ll m)
{
if(n<m||m<0)return 0;
return fac[n]*jv[n-m]%mod;
}
欧拉筛法
详见 筛法。
void sieve()
{
vis[0]=vis[1]=1;
int cnt=0;
for(int i=2;i<N;i++)
{
if(!vis[i])pri[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(i*pri[j]>=N)break;
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
}
}
}
随机数(mt19937)
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dist(1,100);
int k=dist(gen);
矩阵
详见 矩阵。
struct Mat
{
int n;
ll a[N][N];
Mat(){memset(a,0,sizeof a);n=0;}
Mat operator*(const Mat &rhs) const
{
Mat res;
res.n=n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
res.a[i][j]=(res.a[i][j]+a[i][k]*rhs.a[k][j])%mod;
}
}
}
return res;
}
Mat operator^(ll rhs) const
{
Mat res,tmp=*this;
res.n=n;
for(int i=0;i<n;i++)res.a[i][i]=1;
while(rhs)
{
if(rhs&1)res=res*tmp;
tmp=tmp*tmp;
rhs>>=1;
}
return res;
}
};
复数
struct Comp
{
double real,imag;
Comp(double real=0.0,double imag=0.0):real(real),imag(imag){}
Comp operator+(const Comp &rhs) const{return Comp(real+rhs.real,imag+rhs.imag);}
Comp operator-(const Comp &rhs) const{return Comp(real-rhs.real,imag-rhs.imag);}
Comp operator*(const Comp &rhs) const{return Comp(real*rhs.real-imag*rhs.imag,real*rhs.imag+rhs.real*imag);}
Comp operator/(const Comp &rhs) const{return Comp((real*rhs.real+imag*rhs.imag)/(rhs.real*rhs.real+rhs.imag*rhs.imag),(imag*rhs.real-real*rhs.imag)/(rhs.real*rhs.real+rhs.imag*rhs.imag));}
};
分数
struct Frac
{
ll p,q;
Frac(ll _p,ll _q):p(_p),q(_q){}
void maintain()
{
if(q<0){p=-p;q=-q;}
ll g=gcd(p,q);
p/=g;q/=g;
}
Frac operator+(const Frac &rhs) const
{
Frac res={p*rhs.q+q*rhs.p,q*rhs.q};
res.maintain();
return res;
}
Frac operator-(const Frac &rhs) const
{
Frac res={p*rhs.q-q*rhs.p,q*rhs.q};
res.maintain();
return res;
}
Frac operator*(const Frac &rhs) const
{
Frac res={p*rhs.p,q*rhs.q};
res.maintain();
return res;
}
Frac operator/(const Frac &rhs) const
{
Frac res={p*rhs.q,q*rhs.p};
res.maintain();
return res;
}
};
数据结构
并查集
详见 并查集。
struct DSU
{
int fa[N];
void init(int n){for(int i=1;i<=n;i++)fa[i]=i;}
int find(int u){return u==fa[u]?u:fa[u]=find(fa[u]);}
void merge(int u,int v){fa[find(u)]=find(v);}
bool query(int u,int v){return find(u)==find(v);}
};
ST 表
详见 ST 表。
struct ST
{
int a[N][30];
void init(int n)
{
for(int i=1;i<=__lg(n);i++)
{
for(int j=1;j<=n-(1<<i)+1;j++)
{
a[i][j]=max(a[i-1][j],a[i-1][j+(1<<(i-1))]);
}
}
}
int query(int l,int r)
{
int k=__lg(r-l+1);
return max(a[k][l],a[k][r-(1<<k)+1]);
}
};
树状数组
详见 树状数组。
struct BIT
{
int c[N];
void add(int u,int v){while(u<N){c[u]+=v;u+=u&-u;}}
int sum(int u){int res=0;while(u){res+=c[u];u-=u&-u;}return res;}
};
线段树
详见 线段树。
struct SEG
{
ll a[N],val[N<<2],tag[N<<2];
void gx(int u,ll v,int len){val[u]+=v*len;tag[u]+=v;}
void push_up(int u){val[u]=val[ls]+val[rs];}
void push_down(int u,int l,int r)
{
gx(ls,tag[u],mid-l+1);
gx(rs,tag[u],r-mid);
tag[u]=0;
}
void build(int u,int l,int r)
{
if(l==r){val[u]=a[l];return;}
build(ls,l,mid);
build(rs,mid+1,r);
push_up(u);
}
void update(int u,int l,int r,int x,int y,ll v)
{
if(x<=l&&r<=y){gx(u,v,r-l+1);return;}
push_down(u,l,r);
if(x<=mid)update(ls,l,mid,x,y,v);
if(y>mid)update(rs,mid+1,r,x,y,v);
push_up(u);
}
ll query(int u,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return val[u];
push_down(u,l,r);
ll res=0;
if(x<=mid)res+=query(ls,l,mid,x,y);
if(y>mid)res+=query(rs,mid+1,r,x,y);
return res;
}
};
平衡树
详见 平衡树。
#include <bits/extc++.h>
using namespace __gnu_pbds;
tree<pair<int,int>,null_type,less<pair<int,int>>,rb_tree_tag,tree_order_statistics_node_update> T;
图论
树链剖分
详见 树链剖分。
vector<int> G[N];
int fa[N],son[N],siz[N],dep[N];
int top[N],dfn[N],rnk[N],out[N];
int cnt=0;
void dfs1(int u)
{
siz[u]=1;
dep[u]=dep[fa[u]]+1;
for(auto v:G[u])
{
if(v==fa[u])continue;
fa[v]=u;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
dfn[u]=++cnt;
rnk[cnt]=u;
if(son[u])dfs2(son[u],t);
for(auto v:G[u])
{
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
out[u]=cnt;
}
最近公共祖先
详见 最近公共祖先。
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
计算几何
#include <bits/stdc++.h>
using namespace std;
const double pi=acos(-1);
const double eps=1e-10;
int sgn(double x){return (x>eps)-(x<-eps);}
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y):x(_x),y(_y){}
Point operator+(Point B){return Point(x+B.x,y+B.y);}
Point operator-(Point B){return Point(x-B.x,y-B.y);}
Point operator*(double k){return Point(x*k,y*k);}
Point operator/(double k){return Point(x/k,y/k);}
bool operator==(Point B){return sgn(x-B.x)==0&&sgn(y-B.y)==0;}
};
double Dis(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
double Dis2(Point A,Point B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);}
typedef Point Vector;
double Dot(Vector A,Vector B){return A.x*B.x+A.y*B.y;}
double Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}
double Len(Vector A){return sqrt(Dot(A,A));}
double Len2(Vector A){return Dot(A,A);}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}