常用板

零. 写在前面

  1. 请将数组开到合适大小。
  2. 请考虑是否开 long long
  3. 文章内容较多,可使用 Ctrl + F 快速定位。

一. 优化

1. 快读快写

inline ll read(){
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
inline void write(ll x){
if (x<0){putchar('-'); x = -x;}
if (x>9)write(x / 10);
putchar(x % 10 + '0');
}

2. cin/cout优化

std::ios::sync_with_stdio(false);
cin.tie(NULL);cout.time(NULL);

二. 数论

1. 快速幂取模

int quickpow(int a,int b,int mod){
int res=1;
while(b){
if(b&1) res=1ll*res*a%mod;
a=1ll*a*a%mod;b>>=1;
}
return res;
}

2. 龟速乘

ll slowmul(ll a,ll b){
a=a%m;b=b%m; ll res=0;
while(b){
if(b&1) res=(res+a)%mod;
a=(a+a)%mod; b>>=1;
}
return res;
}

3. GCD与LCM

int gcd(int a,int b){
return b==0?a:gcd(b,a/b);
}
int lcm(int a,int b){
return a/gcd(a,b)*b;
}

4. 扩展欧几里得定理

int exgcd(int a,int b,int&x,int&y){
if(!b){x=1,y=0;return a;}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}

5. 组合数取模

int fac[N],inv[N];
void init(){
fac[0]=fac[1]=1;
for(int i=2;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
inv[n]=quickpow(fac[n],mod-2);
for(int i=n-1;i>=0;i--) inv[i]=(1ll*inv[i+1]*(i+1))%mod;
}
int C(int a,int b){
return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;
}

5.1. Lucas 定理

int lucas(int n,int m){
if(m==0) return 1;
else return 1ll*C(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
}

6. 欧拉筛

bool vst[N];
int prime[N],cnt;
void sieve(){
for(int i=2;i<=n;i++){
if(!vst[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&1ll*prime[j]*i<=n;j++){
notprime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
return ;
}

7. 求逆元

7.1. 线性求逆元

void inverse(){
inv[1]=1;
for(int i=1;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}

7.2. 求单个逆元

int inverse(int a,int m){
int x,int y; exgcd(a,m,x,y);
return (x%mod+mod)%mod;
}

8. 矩阵快速幂

struct matrix{int num[N][N];};
matrix operator*(const matrix&a,const matrix&b){
matrix c; memset(c.num,0,sizeof(c.num));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j]%mod)%mod;
}
}
}
return c;
}
matrix matrixpow(matrix a,int b){
matrix ans; memset(ans.num,0,sizeof(ans));
for(int i=1;i<=n;i++) ans.num[i][i]=1;
while(b){
if(b&1) ans=ans*a;
a=a*a; b>>=1;
}
return ans;
}

9. 高斯-约当消元

void gauss(){
for(int i=1;i<=n;i++){
int maxn=i;
for(int j=i+1;j<=n;j++){
if(fabs(a[j][i])>fabs(a[maxn][i])) maxn=j;
}
for(int j=1;j<=n+1;j++) swap(a[i][j],a[maxn][j]);
if(fabs(a[i][i])<eps){cout<<"No solution";return ;}
for(int j=n+1;j>=1;j--) a[i][j]=a[i][j]/a[i][i];
for(int j=1;j<=n;j++){
if(j==i) continue;
double t=a[j][i]/a[i][i];
for(int k=1;k<=n+1;k++) a[j][k]-=a[i][k]*t;
}
}
for(int i=1;i<=n;i++) cout<<a[i][n+1]<<endl;
return ;
}

9.1 矩阵求逆

void gauss(){
for(int i=1;i<=n;i++){
int maxn=i;
for(int j=i+1;j<=n;j++){
if(a[j][i]>a[maxn][i]) maxn=j;
}
for(int j=1;j<=n*2;j++) swap(a[i][j],a[maxn][j]);
if(a[i][i]==0){cout<<"No Solution";return ;}
ll inv=inverse(a[i][i],mod);
for(int j=1;j<=n;j++){
if(i==j) continue;
int t=a[j][i]*inv%mod;
for(int k=i;k<=2*n;k++) a[j][k]=((a[j][k]-t*a[i][k])%mod+mod)%mod;
}
for(int j=1;j<=n*2;++j) a[i][j]=(a[i][j]*inv%mod);
}
for(int i=1;i<=n;i++){
for(int j=n+1;j<=n*2;j++) cout<<a[i][j]<<" ";
cout<<endl;
}
return ;
}

10. 求欧拉函数

10.1. 求单个欧拉函数

ll euler(ll x){
ll res=x;
for(ll i=2;i*i<=x;i++){
if(x%i==0){
res=res/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x!=1) res=res/x*(x-1);
return res;
}

10.2. 线性求欧拉函数

void get_phi(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vst[i]){
vst[i]=1;prime[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
vst[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}

三. 高精度

1. 高精度加法

string add(string a,string b){
ll la=a.size(),lb=b.size(),lc=max(la,lb);
ll na[N]={0},nb[N]={0},nc[N]={0};
string c="";
for(int i=la,j=0;i>=1;i--,j++) na[i]=a[j]-'0';
for(int i=lb,j=0;i>=1;i--,j++) nb[i]=b[j]-'0';
for(int i=1;i<=lc;i++){
nc[i]+=(na[i]+nb[i]);
if(nc[i]>=10) nc[i+1]++,nc[i]-=10;
}
if(nc[lc+1]) lc++;
for(int i=lc;i>=1;i--) c+=(nc[i]+'0');
return c;
}

2. 高精度减法

string minus(string a,string b){
bool flag=0;
if(b.size()>a.size()||a.size()==b.size()&&a<b){
swap(a,b);
flag=1;
}
ll la=a.size(),lb=b.size(),lc=la;
ll na[10009]={0},nb[10009]={0},nc[10009]={0};
string c="";
if(flag) c+='-';
for(int i=0,j=la;i<la;i++,j--) na[j]=a[i]-'0';
for(int i=0,j=lb;i<lb;i++,j--) nb[j]=b[i]-'0';
for(int i=1;i<=la;i++){
nc[i]=na[i]-nb[i];
if(nc[i]<0) nc[i]+=10,na[i+1]--;
}
while(nc[lc]==0&&lc>1) lc--;
for(int i=lc;i>=1;i--) c+=(nc[i]+'0');
return c;
}

3. 高精度乘法

string mul(string a,string b){
ll la=a.size(),lb=b.size(),lc=la+lb;
ll na[N]={0},nb[N]={0},nc[N]={0};
string c="";
for(int i=0,j=la;j>=1;i++,j--) na[j]=a[i]-'0';
for(int i=0,j=lb;j>=1;i++,j--) nb[j]=b[i]-'0';
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++) nc[i+j-1]+=(na[i]*nb[j]);
}
for(int i=1;i<=lc;i++){
if(nc[i]>=10){
nc[i+1]+=nc[i]/10;
nc[i]%=10;
}
}
while(nc[lc]==0&&lc>1) lc--;
for(int i=lc;i>=1;i--) c+=(nc[i]+'0');
return c;
}

4. 高精度除法

string divide(string a,ll b){
ll na[N]={0},nb[N]={0},nc[N]={0};
ll res=0;
string c="";
for(int i=0;i<a.size();i++) na[i]=a[i]-'0';
for(int i=0;i<a.size();i++){
res=res*10+na[i];
nc[i]=res/b;
res%=b;
}
ll i=0;
while(nc[i]==0&&i<a.size()) i++;
if(i==a.size()) return "0";
for(;i<a.size();i++) c+=(nc[i]+'0');
return c;
}

5. 高精度取模

int getmod(string a,int b){
int res=0;
for(int i=0;i<a.size();i++) res=(res*10+(a[i]-'0'))%b;
return res;
}

四. 数据结构

1. 并查集

int id[N];
int root(int x){return id[x]==x?x:id[x]=root(id[x]);}
void unite(int x,int y){
int fx=root(x),fy=root(y);
id[fx]=fy;
return ;
}

2. 树状数组

int bit[N];
int lsb(ll x){return x&(-x);}
void add(int x,int p){
while(x<=n){bit[x]+=p;x+=lsb(x);}
return ;
}
int query(int x){
int ans=0;
while(x){ans+=bit[x];x-=lsb(x);}
return ans;
}

2.1. 区间修改单点查询

void LSB(int x){return x&(-x);}
void add(int x,int d){
while(x<=n){BIT[x]+=d;x+=LSB(x);}
}
void change(int l,int r,int d){add(l,d);add(r+1,-d);}
int query(int x){
int ans=0;
while(x){ans+=BIT[x];x-=LSB(x);}
return ans;
}

2.2. 区间修改区间查询

void add(int x,int d1,int d2){
while(x<=n){
BIT1[x]+=d1; BIT2[x]+=d2;
x+=LSB(x);
}
}
int query1(int x){
int ans=0;
while(x){ans+=BIT1[x];x-=LSB(x);}
return ans;
}
int query2(int x){
int ans=0;
while(x){ans+=BIT2[x];x-=LSB(x);}
return ans;
}
void update(int l,int r,int d){
add(l,d,d*(l-1));
add2(r+1,-d,-d*r);
}
void query(int l,int r){
return r*query1(r)-query2(r)-(l-1)*query(l-1)+query2(l-1);
}

2.3. 二维区间修改区间查询

void add(int x,int y,int d){
for(int i=x;i<=n;i+=LSB(i)){
for(int j=y;j<=m;j+=LSB(j)){
t1[i][j]+=d; t2[i][j]+=x*d;
t3[i][j]+=y*d; t4[i][j]+=x*y*d;
}
}
}
void update(int a,int b,int c,int d,int delta){
add(a,b,delta); add(c+1,d+1,delta);
add(a,d+1,-delta); add(c+1,b,-delta);
}
int sum(int x,int y){
int ans=0;
for(int i=x;i;i-=LSB(i)){
for(int j=y;j;j-=LSB(j)){
ans+=(x+1)*(y+1)*t1[i][j]-(y+1)*t2[i][j]-(x+1)*t3[i][j]+t4[i][j];
}
}
return ans;
}
void query(int a,int b,int c,int d){
return sum(c,d)+sum(a-1,b-1)-sum(c,b-1)-sum(a-1,d);
}

2.4. 康托展开

int cantor(){
fac[0]=1; int res=0;
for(int i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%MOD;
for(int i=n;i>=1;i--){cnt[i]=query(a[i]-1);add(a[i],1);}
for(int i=1;i<=n;i++) res=(res+(cnt[i]*jc[n-i])%MOD)%MOD;
return res;
}

3. ST表

ll LOG2[N],st[N][N];
void init(){
LOG2[1]=0;
for(int i=1;i<=n;i++) LOG2[i]=LOG2[i>>1]+1;
}
void ST(){
for(int i=1;i<=n;i++) st[0][1]=x[i];
ll p=LOG2[n]/LOG2[2];
for(int k=1;k<=p;k++){
for(int i=1;i<=n-(1<<k)+1;i++){
st[k][i]=max(st[k-1][i],st[k-1][i+(1<<(k-1))]);
}
}
}
ll query(ll l,ll r){
ll p=LOG2[r-l+1]/LOG2[2];
return max(st[p][l],st[p][r-(1<<p)+1]);
}

4. 线段树

struct segment_tree{
int l,r,sum,tag;
}tree[N*4];
void pushup(int p){
int ls=p*2,rs=p*2+1;
tree[p].sum=tree[ls].sum+tree[rs].sum;
}
void pushdown(int p){
int ls=p*2,rs=p*2+1;
tree[ls].sum+=(tree[p].tag*(tree[ls].r-tree[ls].l+1));
tree[rs].sum+=(tree[p].tag*(tree[rs].r-tree[rs].l+1));
tree[ls].tag+=tree[p].tag;
tree[rs].tag+=tree[p].tag;
tree[p].tag=0;
}
void build(int p,int l,int r){
tree[p].l=l,tree[p].r=r,tree[p].tag=0;
if(l==r){tree[p].sum=a[l];return ;}
int mid=l+(r-l)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void update(int p,int L,int R,int z){
if(tree[p].l>=L&&tree[p].r<=R){
tree[p].sum+=c*(tree[p].r-tree[p].l+1);
tree[p].tag+=c;
return ;
}
pushdown(p);
int mid=tree[p].l+(tree[p].r-tree[p].l)/2;
if(mid>=L) update(p*2,L,R,z);
if(mid+1<=R) update(p*2+1,L,R,z);
}
int query(int p,int L,int R){
if(tree[p].l>=L&&tree[p].r<=R) return tree[p].sum;
pushdown(p);
int res=0,mid=tree[p].l+(tree[p].r-tree[p].l)/2;
if(mid>=L) res+=query(p*2,L,R);
if(mid+1<=R) res+=query(p*2+1,L,R);
}

4.1. 扫描线

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1600009;
ll n,cnt,tag[N],len[N],idx[N],ans,num;
struct scanline{
ll y,lx,rx,io;
}line[N];
bool cmp(const scanline&a,const scanline&b){
return a.y<b.y;
}
void pushup(int p,int l,int r){
int ls=p*2,rs=p*2+1;
if(tag[p]) len[p]=idx[r]-idx[l];
else if(l+1==r) len[p]=0;
else len[p]=len[ls]+len[rs];
}
void update(int p,int l,int r,int L,int R,ll add){
if(L<=l&&R>=r){
tag[p]+=add;
pushup(p,l,r);
return ;
}
if(l+1==r) return ;
int mid=l+(r-l)/2;
if(L<=mid) update(p*2,l,mid,L,R,add);
if(R-1>=mid) update(p*2+1,mid,r,L,R,add);
pushup(p,l,r);
return ;
}
int main(){
cin>>n;
for(ll i=1;i<=n;i++){
ll a,b,c,d; cin>>a>>b>>c>>d;
line[++cnt]=((scanline){b,a,c,1});
idx[cnt]=a;
line[++cnt]=((scanline){d,a,c,-1});
idx[cnt]=c;
}
sort(idx+1,idx+1+cnt);
sort(line+1,line+1+cnt,cmp);
num=unique(idx+1,idx+1+cnt)-(idx+1);
for(int i=1;i<=cnt;i++){
int L,R;
ans+=(len[1]*(line[i].y-line[i-1].y));
L=lower_bound(idx+1,idx+num+1,line[i].lx)-idx;
R=lower_bound(idx+1,idx+num+1,line[i].rx)-idx;
update(1,1,num,L,R,line[i].io);
}
cout<<ans;
return 0;
}

4.2. 逆康托展开

void pushup(int p){
int ls=p*2,rs=p*2+1;
t[p].cnt=t[ls].cnt+t[rs].cnt;
}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].cnt=1;return ;}
int mid=l+(r-l)/2;
build(p*2,l,mid);build(p*2+1,mid+1,r);
pushup(p);
}
int modify(int p,int x){
if(t[p].l==t[p].r){t[p].cnt=0; return t[p].l;}
int res=0,ls=p*2,rs=p*2+1;
if(x<=t[ls].cnt) res=modify(ls,x);
else res=modify(rs,x-t[ls].cnt);
pushup(p);
return res;
}

4.3 可持久化线段树

struct t{
int ls,rs,val;
}tree[3500009];
int update(int pre,int l,int r,int x){
int t=++cnt;
tree[t].ls=tree[pre].ls;
tree[t].rs=tree[pre].rs;
tree[t].val=tree[pre].val+1;
int mid=l+(r-l)/2;
if(l==r) return t;
if(x<=mid) tree[t].ls=update(tree[pre].ls,l,mid,x);
else tree[t].rs=update(tree[pre].rs,mid+1,r,x);
return t;
}
int query(int l,int r,int L,int R,int k){
if(l>=r) return l;
int x=tree[tree[R].ls].val-tree[tree[L].ls].val;
int mid=l+(r-l)/2;
if(x>=k) return query(l,mid,tree[L].ls,tree[R].ls,k);
else return query(mid+1,r,tree[L].rs,tree[R].rs,k-x);
}

5. 单调队列

l=1,r=1;
for(int i=1;i<=n;i++){
while(l<r&&i-q[l]>=k) l++;
while(l<r&&x[i]>x[q[r-1]]) r--;
q[r++]=i;
maxn[i]=x[q[l]];
}
//最大值
l=1,r=1;
for(int i=1;i<=n;i++){
while(l<r&&i-q[l]>=k) l++;
while(l<r&&x[i]<x[q[r-1]]) r--;
q[r++]=i;
minn[i]=x[q[l]];
}
//最小值

6. 平衡树

6.1. FHQ Treap

struct node{
int ls,rs,val,pri,sze;
}tree[N];
void newnode(int x){
t[++cnt].sze=1;t[cnt].ls=t[cnt].rs=0;
t[cnt].val=x;t[cnt].pri=rand();
}
void pushup(int x){
tree[x].sze=tree[ls].sze+tree[rs].sze+1;
}
void split(int u,int x,int&L,int&R){
if(u==0){L=R=0;return ;}
if(tree[u].val<=x){L=u;split(tree[u].rs,x,tree[u].rs,R);}
else{R=u;split(tree[u].ls,x,L,tree[u].ls);}
}
int merge(int L,int R){
if(L==0||R==0) return L+R;
if(tree[L].pri>tree[R].pri){tree[L].rs=merge(tree[L].rs,R);return L;}
else{tree[R].ls=merge(L,tree[R].ls);return R;}
}
void insert(int x){
int L,R;split(root,x,L,R);
newnode(x);
int tr=merge(L,cnt);
root=merge(tr,R);
}
void del(int x){
int L,R,p;
split(root,x,L,R);
split(L,x-1,L,p);
int tr=merge(tree[p].ls,tree[p].rs);
root=merge(merge(L,tr),R);
}
int rank(int x){
int L,R;split(root,x-1,L,R);
int ans=tree[L].sze+1;
root=merge(L,R);
return ans;
}
int kth(int u,int k){
if(k==tree[tree[u].ls].sze+1) return u;
if(k<tree[tree[u].ls].sze) return kth(tree[u].ls,k);
else return kth(tree[u].rs,k-tree[tree[u].ls].sze-1);
}
int pre(int x){
int L,R;split(root,x-1,L,R);
int ans=t[kth(L,t[L].sze)].val;
root=merge(L,R);
return ans;
}
int nxt(int x){
int L,R;split(root,x,L,R);
int ans=t[kth(R,1)].val;
root=merge(L,R);
return ans;
}

6.2 文艺平衡树

struct node{
int pri,val,ls,rs,tag,sze;
}t[100009];
void newnode(int x){
t[++cnt].sze=1;
t[cnt].val=x;t[cnt].pri=rand();
t[cnt].ls=t[cnt].rs=t[cnt].tag=0;
}
void pushdown(int p){
if(t[p].tag){
swap(t[p].ls,t[p].rs);
t[t[p].ls].tag^=1;t[t[p].rs].tag^=1;
t[p].tag=0;
}
}
void update(int p){
t[p].sze=t[t[p].ls].sze+t[t[p].rs].sze+1;
}
void split(int u,int x,int&L,int&R){
if(u==0){L=R=0;return ;}
pushdown(u);
if(t[t[u].ls].sze+1<=x){L=u;split(t[u].rs,x-t[t[u].ls].sze-1,t[u].rs,R);}
else{R=u;split(t[u].ls,x,L,t[u].ls);}
update(u);
}
int merge(int L,int R){
if(L==0||R==0) return L+R;
if(t[L].pri>t[R].pri){
pushdown(L);t[L].rs=merge(t[L].rs,R);
update(L); return L;
}
else{
pushdown(R);t[R].ls=merge(L,t[R].ls);
update(R); return R;
}
}
void flip(int x,int y){
int L,R,p;
split(root,y,L,R);split(L,x-1,L,p);
t[p].tag^=1;
root=merge(merge(L,p),R);
}
void inorder(int u){
if(u==0) return ;
pushdown(u);
inorder(t[u].ls); cout<<t[u].val<<" "; inorder(t[u].rs);
}

7. 树链剖分

void dfs_son(int x,int father){
fa[x]=father; sze[x]=1; dep[x]=dep[fa[x]]+1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x]) continue;
dfs_son(y,x);
sze[x]+=sze[y];
if(sze[y]>sze[son[x]]) son[x]=y;
}
return ;
}
void dfs_top(int x,int topx){
id[x]=++total; top[x]=topx; xid[total]=x;
if(!son[x]) return ;
dfs_top(son[x],topx);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x]||y==son[x]) continue;
dfs_top(y,y);
}
}
void addtag(int p,int len,int d){
tag[p]+=d;
tree[p]=(tree[p]+d*len)%mod;
}
void pushdown(int p,int l,int r){
if(!tag[p]) return ;
int ls=p*2,rs=p*2+1;
int mid=l+(r-l)/2;
addtag(ls,mid-l+1,tag[p]);
addtag(rs,r-mid,tag[p]);
tag[p]=0;
}
void pushup(int p){
int ls=p*2,rs=p*2+1;
tree[p]=(tree[ls]+tree[rs])%mod;
}
void build(int p,int l,int r){
if(l==r){
tree[p]=a[xid[l]]%mod;
return ;
}
int mid=l+(r-l)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void update(int p,int l,int r,int L,int R,int d){
if(L<=l&&R>=r){
addtag(p,r-l+1,d);
return ;
}
pushdown(p,l,r);
int mid=l+(r-l)/2;
if(mid>=L) update(p*2,l,mid,L,R,d);
if(mid+1<=R) update(p*2+1,mid+1,r,L,R,d);
pushup(p);
}
ll query(int p,int l,int r,int L,int R){
if(L<=l&&R>=r) return tree[p]%mod;
pushdown(p,l,r);
ll res=0; int mid=l+(r-l)/2;
if(mid>=L) res=(res+query(p*2,l,mid,L,R))%mod;
if(mid+1<=R) res=(res+query(p*2+1,mid+1,r,L,R))%mod;
return res;
}
void update_range(int x,int y,int z){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,id[x],id[y],z);
}
ll query_range(int x,int y){
ll res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=(res+query(1,1,n,id[top[x]],id[x]))%mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
res=(res+query(1,1,n,id[x],id[y]))%mod;
return res;
}
void update_tree(int x,int k){
update(1,1,n,id[x],id[x]+sze[x]-1,k);
}
ll query_tree(int x){
return query(1,1,n,id[x],id[x]+sze[x]-1)%mod;
}

五. 图论

1. 链式前向星

void addedge(int u,int v,int w){
nxt[++tot]=head[u];head[u]=tot;
to[tot]=v;ver[tot]=w;
}

2. Floyd

void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
}
}
}

2.1. bitset 优化 Floyd

bitset<N> d;
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
if(d[i][k]) d[i]|=d[k];
}
}
}

3. Dijkstra堆优化

struct node{
int pos,dst;
bool operator<(const node&x)const{
return dst>x.dst;
}
};
int dst[N];
bool vst[N];
void dijkstra(){
priority_queue<node> q;
memset(d,INF,sizeof(d));
dst[s]=0;
q.push((node){s,0});
while(!q.empty()){
int fnt=q.top().pos; q.pop();
if(vst[fnt.pos]) continue;
vst[fnt.pos]=1;
for(int i=head[fnt];i;i=nxt[i]){
int y=to[i];
if(dst[y]>dst[fnt.pos]+ver[i]){
dst[y]=dst[fnt.pos]+ver[i];
q.push((node){y,dst[y]});
}
}
}
return ;
}

4. SPFA

int dst[N];
bool in[N];
void SPFA(){
memset(dis,INF,sizeof(dis));
queue<int> q;
in[s]=1;dst[s]=0;
q.push(s);
while(!q.empty()){
int fnt=q.front();q.pop();
in[fnt]=0;
for(int i=head[fnt];i;i=nxt[i]){
int y=to[i];
if(dst[y]>dst[fnt]+ver[i]){
dst[y]=dst[fnt]+ver[i];
if(!in[y]){in[y]=1;q.push(y);}
}
}
}
return ;
}

4.1. SPFA判负环

int dst[N],cnt[N];
bool in[N];
void SPFA(){
memset(dis,INF,sizeof(dis));
queue<int> q;
in[s]=1;dst[s]=0;cnt[s]=1;
q.push(s);
while(!q.empty()){
int fnt=q.front();q.pop();
in[fnt]=0;
for(int i=head[fnt];i;i=nxt[i]){
int y=to[i];
if(dst[y]>dst[fnt]+ver[i]){
dst[y]=dst[fnt]+ver[i]; cnt[y]++;
if(cnt[y]>=n+1) return 1;
if(!in[y]){in[y]=1;q.push(y);}
}
}
}
return 0;
}

5. Kruskal

struct edge{int x,y,w;}e[N];
bool cmp(const edge&a,const edge&b){return a.w<b.w;}
void Kruskal(){
int ans=0,res=n;
sort(e+1,e+1+m,cmp);
for(int i=1;i<=m;i++){
if(root(e[i].x)==root(e[i].y)) continue;
ans+=e[i].z;
unite(e[i].x,e[i].y);
tot--;
if(tot==1) return ans;
}
return -1;
}

6. 最近公共祖先

ll p[N][21],dep[N];
void dfs(int x,int fa){
p[x][0]=fa; dep[x]=dep[fa]+1;
for(int i=1;i<=20;i++) p[x][i]=p[p[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa) continue;
dfs(y,x);
}
return ;
}
int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--){
if(dep[p[x][i]]>=dep[y]) x=p[x][i];
}
if(x==y) return x;
for(int i=20;i>=0;i--){
if(p[x][i]!=p[y][i]){x=p[x][i];y=p[y][i];}
}
return p[x][0];
}

7. 图的连通性

7.1. 割点

void tarjan(int x,int fa){
dfn[x]=low[x]=++tot;
int cnt=0;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!dfn[y]){
tarjan(y,x);
low[x]=min(low[x],low[y]);
if(x==fa) cnt++;
else if(low[y]>=dfn[x]&&!flag[x]) flag[x]=1;
}
low[x]=min(low[x],low[y]);
}
if(x==fa&&cnt>1) flag[x]=1;
return ;
}

7.2. 割边

void tarjan(int x,int fa){
dfn[x]=low[x]=++tot;
int cnt=0;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!dfn[y]){
tarjan(y,x);
low[x]=min(low[x],low[y]);
if(x==fa) cnt++;
else if(low[y]>dfn[x]&&!flag[x]) flag[x]=1;
}
low[x]=min(low[x],low[y]);
}
if(x==fa&&cnt>1) flag[x]=1;
return ;
}

7.3 缩点

void tarjan(int x){
stk[++top]=x;
dfn[x]=low[x]=++total;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(id[y]) continue;
if(!dfn[y]) tarjan(y);
low[x]=min(low[x],low[y]);
}
if(low[x]==dfn[x]){
cnt++;
while(stk[top+1]!=x){
num[cnt].push_back(stk[top]);
id[stk[top]]=cnt;
top--;
}
}
}

8. 拓扑排序

void topo(){
queue<int> q;
for(int i=1;i<=n;i++){
if(in[i]==0) q.push(i);
}
int cnt=0;
while(!q.empty()){
int fnt=q.front();q.pop();
tp[++cnt]=fnt;
for(int i=head[fnt];i;i=nxt[i]){
int y=to[i];in[i]--;
if(in[i]==0) q.push(i);
}
}
return ;
}

六. 字符串

1. Hash

ull hash(string s){
ull P=13131;pow[0]=1;
int n=s.size();
for(int i=0;i<n;i++){
H[i]=H[i-1]*P+(s[i]-'a');
pow[i]=pow[i-1]*P;
}
}
ull get_hash(int l,int r){
return H[r]-H[l-1]*pow[r-l+1];
}

2. 字典树

struct node{
int cnt,end,nxt[26];
}tree[N];
int tot=1;
void insert(string s){
int now=1;
for(int i=0;i<s.size();i++){
if(tree[now].nxt[s[i]-'a']==0) tree[now].nxt[s[i]-'a']=++tot;
now=tree[now].nxt[s[i]-'a'];
tree[now].cnt++;
}
tree[now].end++;
}
int query(string s){
int now=1;
for(int i=0;i<s.size();i++){
if(tree[now].nxt[s[i]-'a']==0) return 0;
now=tree[now].nxt[s[i]-'a'];
}
return tree[now].cnt;
}

3. KMP

void kmp(string s1,string s2){
ll len1=s1.size();
ll len2=s2.size();
for(int i=1;i<len2;i++){
while(pos!=0&&s2[i]!=s2[pos]) pos=kmp[pos];
if(s2[pos]==s2[i]) pos++;
kmp[i+1]=pos;
}
ll pos=0;
for(int i=0;i<len1;i++){
while(pos!=0&&s2[pos]!=s1[i]) pos=kmp[pos];
if(s2[pos]==s1[i]) pos++;
if(pos==len2){
cout<<i-len2+2<<endl;
pos=kmp[pos];
}
}
}

4. Manacher

int manacher(){
int k=0,R=0,C=0;
str[k++]='$'; str[k++]='#';
for(int i=0;i<n;i++){
str[k++]=s[i];
str[k++]='#';
}
str[k++]='&';
n=k;
for(int i=1;i<n;i++){
if(i<R) p[i]=min(p[2*C-i],C+p[C]-i);
else p[i]=1;
while(str[i+p[i]]==str[i-p[i]]) p[i]++;
if(p[i]+i>R){R=p[i]+i;C=i;}
ans=max(ans,p[i]);
}
return ans-1;
}

七. 递推/动态规划

1. 01背包

int f[N],w[N],v[N];
void bb01(){
for(int i=1;i<=n;i++){
for(int j=W;j>=w[j];j--) f[j]=max(f[j],f[j-w[j]]+v[j]);
}
}

2. 完全背包

int f[N],w[N],v[N];
void bbINF(){
for(int i=1;i<=n;i++){
for(int j=w[j];j<=W;j++) f[j]=max(f[j],f[j-w[j]]+v[j]);
}
}

八. 前缀和与差分

1. 二维前缀和

int a[N][N],s[N][N];
void sum(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
s[i][j]=a[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
return ;
}

九. 更新记录

2023/08/14:优化了排版;重写快速幂扩欧算法组合数取模并查集树状数组SPFASPFA判负环;新增求逆元高精度取模龟速乘矩阵快速幂高斯消元法Manacher

2023/08/15:优化了排版;合并 树论图论;重写 线段树Kruskal;增加 链式前向星Floydbitset 优化 Floyd树状数组拓展割点拓扑排序字典树FHQ Treap文艺平衡树Hash

2023/08/16:使用 链式前向星 重写 图论 板块,重写 最近公共祖先;增加 树链剖分割边缩点求欧拉函数Lucas 定理扫描线(逆)康托展开

2023/08/17:增加 可持久化线段树

203/08/19:修正了几处错误;新增 矩阵求逆

posted @   11jiang08  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示