代码模板库
图论
tarjan+缩点:
//有向图tarjan缩点 void add(int a,int b) { bian[++ecnt].to=b; bian[ecnt].nxt=head[a]; head[a]=ecnt; } void add1(int a,int b)//函数名称容易出锅,以后要用有区分度的名称 { tu[++rcnt].to=b; tu[rcnt].nxt=headtu[a]; headtu[a]=rcnt; } void tarjan(int u) { dfn[u]=low[u]=++tim;// stk[++tk]=u;//入栈 vis[u]=true;//入栈标记 for(int i=head[u];i;i=bian[i].nxt) { int v=bian[i].to; if(!dfn[v]) { tarjan(v); low[u]=min(low[v],low[u]); } else if(vis[v])//注意这附近的if else 括号匹配,多次出锅 low[u]=min(low[v],low[u]); } if(dfn[u]==low[u]) { num++; while(stk[tk]!=u) { vis[stk[tk]]=false; shuyu[stk[tk]]=num; stk[tk]=0; tk--; }//可以用do while代替,用while的话执行完要再来一次 vis[stk[tk]]=false; shuyu[stk[tk]]=num;//记录属于哪个联通块 stk[tk]=0;//出栈 tk--; } } void suo()//枚举点和边,原来的边左右两点如果不在同一联通块,则建新边 { for(int i=1;i<=n;i++) { int u=shuyu[i]; shd[u]+=dian[i]; for(int j=head[i];j;j=bian[j].nxt) { int v=bian[j].to; if(shuyu[v]!=u) { add1(u,shuyu[v]); } } } } int main() { n=read();m=read(); int a,b; for(int i=1;i<=n;i++) dian[i]=read(); for(int i=1;i<=m;i++) { a=read();b=read(); add(a,b); } for(int i=1;i<=n;i++) { if(!dfn[i])//注意这里,整个图不一定是连通图,所以要遍历整个图 tarjan(i); } suo();//缩点 for(int i=1;i<=num;i++) ans=max(ans,dfs(i)); cout<<ans; return 0; }
tarjan求点双:
void tarjan(int x) { dfn[x]=low[x]=++tim; int flag=0; for(int i=head[x];i;i=bian[i].nxt) { int y=bian[i].to; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { flag++; if((x!=rof||flag>1)&&gee[x]==0) ge[++cnt]=x,gee[x]=1;//you chong fu } } else low[x]=min(low[x],dfn[y]); } } ~int main for(int i=1;i<=n;i++) { if(!dfn[i]) rof=i,tarjan(i); }
tarjan求边双:
void tarjan(int u,int bian) { dfn[u]=low[u]=++tim; for(int i=head[u];i;i=bian[i].nxt) { int v=bian[i].to; if(!dfn[v]) { tarjan(v,i); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) isbridge[i]=isbridge[i^1]=1; } else if(i!=(bian^1)) low[u]=min(low[u],dfn[v]); } } ~int main for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0);
最小生成树(prim):
//prim void prim() { memset(dis,0x3f,sizeof dis); dis[1]=0; int b=1; for(int j=1;j<=n;j++) { vis[b]=true;cnt++;ans+=dis[b]; for(int i=head[b];i;i=bian[i].nxt) { int c=bian[i].to; int d=bian[i].quan; if(d<dis[c])dis[c]=d; } mx=0x3f3f3f3f; for(int i=1;i<=n;i++) { if(dis[i]<mx&&vis[i]==false) { mx=dis[i]; b=i; } } } }
最短路(dijstra):
void dij() { memset(dis,0x3f,sizeof(dis)); int qi=s; dis[qi]=0; q.push(bbb{qi,0}); while(!q.empty()) { bbb w=q.top(); int k=w.jiedian; q.pop(); if(!vis[k]) { vis[k]=true; for(int i=head[k];i;i=bian[i].nxt) { int v=bian[i].to; if(dis[v]>dis[k]+bian[i].leng) { dis[v]=dis[k]+bian[i].leng; q.push(bbb{v,dis[v]}); } } } } }
最短路(SPFA):(忘了急需复习
#include<bits/stdc++.h> using namespace std; int n,m,s; int a,b,c; int dis[100005]; bool vis[100005]; int head[100005],ecnt; struct aaa { int jiedian,dis; }; bool operator <(const aaa& a,const aaa& b){ return a.dis>b.dis; } priority_queue<aaa>q; struct edge{ int to,nxt,dis; }ed[200010]; void addedge(int f,int to,int dis) { ed[++ecnt].to=to; ed[ecnt].dis=dis; ed[ecnt].nxt=head[f]; head[f]=ecnt; } inline int read() { int x=0; char c=getchar(); bool flag=0; while(c<'0'||c>'9'){if(c=='-')flag=1; c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return flag?-x:x; } void suanfa() { memset(dis,0x3f,sizeof dis); int k=s; dis[s]=0; for(int i=head[k];i!=0;i=ed[i].nxt) { int v=ed[i].to;//ed xianduan if(dis[v]>dis[k]+ed[i].dis) { q.push(aaa{ed[i].to,dis[k]+ed[i].dis}); dis[v]=dis[k]+ed[i].dis; } } while(!q.empty()) { aaa w=q.top(); int k=w.jiedian; q.pop(); if(vis[k]==false) { vis[k]=true;//mark white; for(int i=head[k];i!=0;i=ed[i].nxt) { int v=ed[i].to;//ed xianduan if(dis[v]>dis[k]+ed[i].dis) { q.push(aaa{ed[i].to,dis[k]+ed[i].dis}); dis[v]=dis[k]+ed[i].dis; } } } } } int main() { n=read();m=read();s=read(); for(int i=1;i<=m;i++) { a=read();b=read();c=read(); addedge(a,b,c); } suanfa(); for(int i=1;i<=n;i++) { if(dis[i]!=0x3f3f3f3f) printf("%d ",dis[i]); else cout<<2147483647<<" "; } return 0; }
倍增lca:
#include<bits/stdc++.h> using namespace std; int n,m,s; int a,b; struct aaa { int to,nxt; }bian[1000001]; int head[500001]; int ecnt; int deep[500001]; bool vis[500001]; int dian[500001][20]; int deepmax; inline int read() { int x=0; char c=getchar(); bool flag=0; while(c<'0'||c>'9'){if(c=='-')flag=1; c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return flag?-x:x; } void dfs(int a) { for(int i=head[a];i;i=bian[i].nxt) { int b=bian[i].to; if(!deep[b]) { deep[b]=deep[a]+1; dian[b][0]=a; dfs(b); } } } void st() { for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) { if(dian[i][j-1]) dian[i][j]=dian[dian[i][j-1]][j-1]; } } void add(int a,int b) { bian[++ecnt].to=b; bian[ecnt].nxt=head[a]; head[a]=ecnt; bian[++ecnt].to=a; bian[ecnt].nxt=head[b]; head[b]=ecnt; } int lca(int a,int b) { if(deep[a]<deep[b])swap(a,b); int i; for(i=0;(1<<i)<=deep[a];i++); i--; for(int j=i;j>=0;j--) { if(deep[a]-(1<<j)>=deep[b]) { a=dian[a][j]; } } if(a==b)return a; for(int j=i;j>=0;j--) { if(dian[a][j]!=0&&dian[a][j]!=dian[b][j]) { a=dian[a][j]; b=dian[b][j]; } } return dian[a][0]; } int main() { n=read();m=read();s=read(); for(int i=1;i<=n-1;i++) { a=read();b=read(); add(a,b); } dian[s][0]=0; deep[s]=1;//初始化深度; dfs(s);//求深度; st(); for(int i=1;i<=m;i++) { a=read();b=read(); int c=lca(a,b); // if(a==s||b==s)cout<<s<<endl; // else printf("%d\n",c); } return 0; }
数学
线性筛:
//线性筛 bool sushu[10000005]; int n,m; int sushubiao[5000005]; int q; void shai() { for(int i=2;i<=n;i++) { if(!sushu[i]) sushubiao[++q]=i; for(int j=1;j<=q&&sushubiao[j]*i<=n;j++) { sushu[sushubiao[j]*i]=true; if(i%sushubiao[j]==0)break; } } }
乘法逆元:
void ny() { inv[1]=1; for(int i=2;i<=n;i++) inv[i]=1ll*(p-(p/i))*inv[p%i]%p; } a^p-2===a^-1 (mod p)
高斯消元:
#include<bits/stdc++.h> using namespace std; const double jd=5e-3; int n; double fc[55][55]; double xi[55]; double jie[55]; inline int read() { int x=0;bool f=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return f?-x:x; } void Gauss() { for(int i=1;i<=n-1;i++)//消第i个未知数; { for(int j=i+1;j<=n;j++) { if(fc[i][i]==0) { for(int k=1;k<=n;k++) { swap(fc[i][k],fc[j][k]); } swap(xi[i],xi[j]); } if(abs(fc[j][i])<jd) continue; double cun=fc[i][i]/fc[j][i]; for(int k=i;k<=n;k++) fc[j][k]=fc[j][k]*cun-fc[i][k]; xi[j]=xi[j]*cun-xi[i]; } } } int jfc() { for(int i=n;i>=1;i--) { double zuo=0,you=xi[i]; for(int j=n;j>i;j--) zuo+=fc[i][j]*jie[j]; you-=zuo; if(abs(fc[i][i])<jd&&abs(you)>jd)return -1; if(abs(fc[i][i])<jd&&abs(you)<jd)return 0; jie[i]=you/fc[i][i]; } return 1; } int main() { n=read(); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) fc[i][j]=read()*1.0; xi[i]=read()*1.0; } Gauss(); switch(jfc()) { case 1: { for(int i=1;i<=n;i++) { if(abs(jie[i])<jd)printf("x%d=0\n",i); else printf("x%d=%.2lf\n",i,jie[i]); } break; } case 0://无穷多解 { cout<<0<<endl; break; } case -1://无解 { cout<<-1<<endl; break; } } }
exgcd:
void exgcd(ll a,ll b) { if(b==0) { x=1;y=0; return; } exgcd(b,a%b); ll tem=x; x=y; y=tem-a/b*y; }
扩展中国剩余定理(excrt):
#include<bits/stdc++.h> using namespace std; #define ll __int128 ll ans,x,y,a,b,c,yu[100005],mo[100005],M,n; long long read() { ll f=1,x=0; char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();} while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();} return f*x; } long long gcd(ll a,ll b) { ll c; while(a%b) { c=a%b; a=b; b=c; } return b; } long long lcm(ll a,ll b) { return a/gcd(a,b)*b; } void exgcd(ll a,ll b) { if(b==0) { x=1;y=0; return; } exgcd(b,a%b); ll tem=x; x=y; y=tem-a/b*y; } long long excrt() { M=mo[1];ans=yu[1]; for(int i=2;i<=n;i++) { exgcd(M,mo[i]); ll gcdd=gcd(M,mo[i]); if((yu[i]-ans)%gcdd!=0)return -1; x*=(yu[i]-ans)/gcdd; ans=ans+x*M; M=M/gcd(M,mo[i])*mo[i]; ans=(ans%M+M)%M; } return ans; } int main() { n=read(); for(ll i=1;i<=n;i++) mo[i]=read(),yu[i]=read(); cout<<excrt(); return 0; }
卢卡斯定理:(小模数的组合数)
#include<bits/stdc++.h> #define ll long long using namespace std; int T; ll n,m,p; ll a[100005]; inline ll read() { bool f=0;ll x=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return f?-x:x; } ll ks(ll x,ll k) { ll num=1; while(k) { if(k&1) num=num*x%p; x=x*x%p; k>>=1; } return num; } ll c(ll n,ll m) { if(m>n)return 0; return ((a[n]*ks(a[m],p-2))%p*ks(a[n-m],p-2)%p); } ll lucas(ll n,ll m) { if(!m)return 1; return c(n%p,m%p)*lucas(n/p,m/p)%p; } int main() { T=read(); while(T--) { n=read();m=read();p=read(); a[0]=1; for(int i=1;i<=p;i++)a[i]=(a[i-1]*i)%p; cout<<lucas(n+m,n)<<endl; } return 0; }
数据结构
树状数组
//树状数组 int lowb(int x){return x&-x;} void add(int x,int k) { for(;x<=n;x+=lowb(x)) s[x]+=k; } long long ask(int a) { long long ans=0; while(a!=0) { ans+=s[a]; a-=lowb(a); } return ans; } //询问l~r: ans=ask(r)-ask(l-1)
线段树
//这是线段树1,如果有乘法,先乘后加即可。 //还有一些线段树的题,是线段树结构和标记的巧妙应用 #include<bits/stdc++.h> using namespace std; const int N=100005; int n,m; int a[N]; struct aaa { int l,r; long long sum,lazy; }t[4*N]; inline int read() { int x=0;bool flag=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')flag=true;c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return flag?-x:x; } void build(int num,int l,int r) { t[num].l=l;t[num].r=r; if(l==r) { t[num].sum=a[l]; return; } int mid=(l+r)/2; build(num*2,l,mid); build(num*2+1,mid+1,r); t[num].sum=t[num*2].sum+t[num*2+1].sum; } void push(int num) { t[2*num+1].sum+=t[num].lazy*(t[2*num+1].r-t[2*num+1].l+1); t[2*num+1].lazy+=t[num].lazy; t[2*num].sum+=t[num].lazy*(t[2*num].r-t[2*num].l+1); t[2*num].lazy+=t[num].lazy; t[num].lazy=0; } void add(int l,int r,int zhi,int num) { int x=t[num].l,y=t[num].r; if(x==l&&y==r) { t[num].lazy+=zhi; t[num].sum+=(r-l+1)*zhi; return; } int mid=(x+y)/2; push(num); if(r<=mid) add(l,r,zhi,2*num); else if(l>mid) add(l,r,zhi,2*num+1); else { add(l,mid,zhi,2*num); add(mid+1,r,zhi,2*num+1); } t[num].sum=t[2*num].sum+t[2*num+1].sum; } long long ask(int l,int r,int num) { int x=t[num].l,y=t[num].r; if(x==l&&y==r)return t[num].sum; int mid=(x+y)/2; if(t[num].lazy)push(num); if(r<=mid) return ask(l,r,2*num); else if(l>mid) return ask(l,r,2*num+1); else return ask(l,mid,2*num)+ask(mid+1,r,2*num+1); } int main() { n=read();m=read(); int e,b,c,d; for(int i=1;i<=n;i++) a[i]=read(); build(1,1,n); for(int i=1;i<=m;i++) { e=read(); if(e==1) { b=read();c=read();d=read(); add(b,c,d,1); } else if(e==2) { b=read();c=read(); long long ans=ask(b,c,1); printf("%lld\n",ans); } } return 0; }
其他
st表:不修改的区间内求最大最小值(无法求和)
//st表模板 //不修改的区间求最大最小值,无法求和 //st[i][j]表示从i开始(包括i),之后2^j的区间内的最大/最小值 for(int i=1;i<=n;i++)//对于自身的预处理 mx[i][0]=a[i]; for(int j=1;(1<<j)<=n;j++)//先循环2的j次方,否则信息不全无法合并。 for(int i=1;i+(1<<j)-1<=n;i++)//i+(1<<j)-1<=n,注意要减1,(想意思) { mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); } for(int i=1;i<=m;i++)//查询 { b=read();c=read(); k=log2(c-b+1);//查询是2的几次方 ans=max(mx[b][k],mx[c-(1<<k)+1][k]));//由于k是向下取整,所以要这样做避免少算。 }
快速幂:
ll ksm(ll x,ll k) { ll num=1; while(k) { if(k&1) num=num*x%p; x=x*x%p; k>>=1; } return num%p; }
三分:
//如果是整数定义域,边界很难处理 while(r-l>=mn) { double a=(2*l+r)/3,b=(l+2*r)/3; if(f(a)>f(b)) r=b; else l=a; }
哈希:
for(int i=1;i<=n;i++) { scanf("%s",a[i]+1); int q=strlen(a[i]+1); for(int j=1;j<=q;j++) hsh[i]=(hsh[i]*139+a[i][j])%100000007; }
快读
inline int read() { int x=0;bool f=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return f?-x:x; }