目录:
1.堆
2.扩展中国剩余定理
3.线段树
4.并查集
5.最小生成树
6.最短路
7.离散化
8.tarjan缩点
9.KMP算法
10.高斯消元法
一.堆(stl版)
1.大根堆
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; priority_queue < int , vector < int > > q; int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int x,y; scanf("%d",&x); if(x==1)//将y插入到堆中 { scanf("%d",&y); q.push(y); } if(x==2)//删除该大根堆内的最大数 { q.pop(); } if(x==3)//输出该大根堆内的最大数 { printf("%d\n",q.top()); } } }
2.小根堆
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; priority_queue < int , vector < int > , greater < int > > q; int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int x,y; scanf("%d",&x); if(x==1)//将y插入到堆中 { scanf("%d",&y); q.push(y); } if(x==2)//删除该小根堆内的最小数 { q.pop(); } if(x==3)//输出该小根堆内的最小数 { printf("%d\n",q.top()); } } }
二.扩展中国剩余定理
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> using namespace std; long long n,ai[100001],bi[100001]; long long mul(long long x,long long y,long long p) { long long ans=0; while(y) { if(y&1) ans=(ans+x)%p; x=(x+x)%p; y>>=1; } return ans; } long long exgcd(long long a,long long b,long long &x,long long &y) { if(b==0) { x=1; y=0; return a; } long long cnt=exgcd(b,a%b,x,y); long long idx=x; x=y; y=idx-a/b*y; return cnt; } long long excrt() { long long x=0,y=0; long long M=bi[1],ans=ai[1]; for(long long i=2;i<=n;i++) { long long a=M,b=bi[i],c=((ai[i]-ans)%b+b)%b; long long gcd=exgcd(a,b,x,y),idx=b/gcd; if(c%gcd!=0) return -1; x=mul(x,c/gcd,idx); ans+=x*M; M*=idx; ans=(ans%M+M)%M; } return (ans%M+M)%M; } int main() { scanf("%lld",&n); for(long long i=1;i<=n;i++) scanf("%lld%lld",&ai[i],&bi[i]); printf("%lld\n",excrt()); }
三.线段树
1.建树
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100001],sum[400001]; void pushup(int k) { sum[k]=sum[k<<1]+sum[k<<1|1]; } void build(int l,int r,int k) { if(l==r) { sum[k]=a[l]; return; } int mid=(l+r)>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); pushup(k); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); }
2.单点修改(单点加同理)
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100001],sum[400001],m; void pushup(int k) { sum[k]=sum[k<<1]+sum[k<<1|1]; } void update(int l,int r,int p,int v,int k) { if(l==r) { sum[k]=v; return; } int mid=(l+r)>>1; if(mid>=p) update(l,mid,p,v,k<<1); if(mid<p) update(mid+1,r,p,v,k<<1|1); pushup(k); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1);//先建树 scanf("%d",&m); for(int i=1;i<=m;i++) { int x,v; scanf("%d%d",&x,&v); update(1,n,x,v,1); } }
3.区间加
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100001],sum[400001],m,tag[400001]; void pushup(int k) { sum[k]=sum[k<<1]+sum[k<<1|1]; } void lazy(int l,int r,int v,int k) { tag[k]+=v; sum[k]+=(r-l+1)*v; } void pushdown(int l,int r,int k) { int mid=(l+r)>>1; lazy(l,mid,tag[k],k<<1); lazy(mid+1,r,tag[k],k<<1|1); tag[k]=0; } void update(int l,int r,int x,int y,int v,int k) { if(x<=l&&r<=y) { sum[k]+=(r-l+1)*v; tag[k]+=v; return; } int mid=(l+r)>>1; pushdown(l,r,k); if(mid>=x) update(l,mid,x,y,v,k<<1); if(mid<y) update(mid+1,r,x,y,k<<1|1); pushup(k); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1);//先建树 scanf("%d",&m); for(int i=1;i<=m;i++) { int x,y,v; scanf("%d%d%d",&x,&y,&v); update(1,n,x,y,v,1); } }
4.区间修改
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100001],sum[400001],m,tag[400001]; void pushup(int k) { sum[k]=sum[k<<1]+sum[k<<1|1]; } void lazy(int l,int r,int v,int k) { tag[k]=v; sum[k]=(r-l+1)*v; } void pushdown(int l,int r,int k) { int mid=(l+r)>>1; lazy(l,mid,tag[k],k<<1); lazy(mid+1,r,tag[k],k<<1|1); tag[k]=0; } void update(int l,int r,int x,int y,int v,int k) { if(x<=l&&r<=y) { sum[k]=(r-l+1)*v; tag[k]=v; return; } int mid=(l+r)>>1; pushdown(l,r,k); if(mid>=x) update(l,mid,x,y,v,k<<1); if(mid<y) update(mid+1,r,x,y,k<<1|1); pushup(k); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1);//先建树 scanf("%d",&m); for(int i=1;i<=m;i++) { int x,y,v; scanf("%d%d%d",&x,&y,&v); update(1,n,x,y,v,1); } }
5.单点查询
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100001],sum[400001],m,tag[400001]; void lazy(int l,int r,int v,int k) { tag[k]=v; sum[k]=(r-l+1)*v; } void pushdown(int l,int r,int k) { int mid=(l+r)>>1; lazy(l,mid,tag[k],k<<1); lazy(mid+1,r,tag[k],k<<1|1); tag[k]=0; } int query(int l,int r,int p,int k) { if(l==r) return sum[k]; int mid=(l+r)>>1,ans=0; pushdown(l,r,k); if(mid>=p) ans+=query(l,mid,p,k<<1); if(mid<p) ans+=query(mid+1,r,p,k<<1|1); return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1);//先建树 scanf("%d",&m); for(int i=1;i<=m;i++) { int x; scanf("%d",&x); int ans=query(1,n,x,1); printf("%d\n",ans); } }
6.区间查询
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100001],sum[400001],m,tag[400001]; void lazy(int l,int r,int v,int k) { tag[k]=v; sum[k]=(r-l+1)*v; } void pushdown(int l,int r,int k) { int mid=(l+r)>>1; lazy(l,mid,tag[k],k<<1); lazy(mid+1,r,tag[k],k<<1|1); tag[k]=0; } int query(int l,int r,int x,int y,int k) { if(x<=l&&r<=y) return sum[k]; int mid=(l+r)>>1,ans=0; pushdown(l,r,k); if(mid>=x) ans+=query(l,mid,x,y,k<<1); if(mid<y) ans+=query(mid+1,r,x,y,k<<1|1); return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1);//先建树 scanf("%d",&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); int ans=query(1,n,x,y,1); printf("%d\n",ans); } }
四.并查集
1.路径压缩
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,m,f[10001]; int find(int p) { if(p!=f[p]) f[p]=find(f[p]); return f[p]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=n;i++) { int x=find(i); printf("%d\n",x); } }
2.普通合并
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,m,f[10001]; int find(int p) { if(p!=f[p]) f[p]=find(f[p]); return f[p]; } void merge(int x,int y) { int fx=find(x),fy=find(y); if(fx!=fy) f[fx]=fy; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); merge(x,y); } }
3.启发式合并
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,m,f[10001],s[10001]; int find(int p) { if(p!=f[p]) f[p]=find(f[p]); return f[p]; } void merge(int x,int y) { int fx=find(x),fy=find(y); if(s[fx]<s[fy]) s[fy]+=s[fx],f[fx]=fy; else s[fx]+=s[fy],f[fy]=fx; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { f[i]=i; s[i]=1; } for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); merge(x,y); } }
五.最小生成树
1.Prim算法
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,l[101][101],minn[101]; bool used[101]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;i++) scanf("%d",&l[i][j]); memset(minn,999999999,sizeof(minn)); minn[1]=0; memset(u,1,sizeof(u)); for(int i=1;i<=n;i++) { int k=0; for(int j=1;j<=n;j++) if(u[j]&&minn[j]<minn[k]) k=j; u[k]=0; for(int j=1;j<=n;j++) if(u[j]&&l[k][j]<minn[j]) minn[j]=g[k][j]; } int ans=0; for(int i=1;i<=n;i++) ans+=minn[i]; prntf("%d\n",ans); }
2.Kruskal算法
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,f[101],m,tot,k,idx; struct Edge { int x,y,v; }a[9001]; bool cmp(const Edge &a,const Edge &b) { return a.v<b.v; } int find(int p) { if(f[p]!=p) f[p]=find(f[p]); return f[p]; } void merge(int x,int y) { int fx=find(x); int fy=find(y); if(fx!=fy) f[fx]=fy; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int value; scanf("%d",&value); a[++idx].x=i; a[idx].y=j; a[idx].v=value; } for(int i=1;i<=n;i++) f[i]=i; sort(a+1,a+idx+1,cmp); for(int i=1;i<=m;i++) { if(find(a[i].x)!=find(a[i.y])) { merge(a[i].x,a[i].y); tot+=a[i].v; k++; } if(k==n-1) break; } printf("%d\n",tot); }
六.最短路
1.Floyed算法
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,f[101][101],s,t; int main() { scanf("%d",&n); memset(f,0x7f,sizeof(f)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&f[i][j]); scanf("%d%d",&s,&t); for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((i!=j)&&(j!=k)&&(j!=k)&&f[i][k]+f[k][j]<f[i][j]) f[i][j]=f[i][k]+f[k][j]; printf("%d",f[s][t]); }
2.Dijkstra算法
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int f[101][101],n,s,t,minn[101]; bool vis[101]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&f[i][j]); scanf("%d%d",&s,&t); for(int i=1;i<=n;i++) minn[i]=f[s][i]; minn[s]=0; vis[s]=1; for(int i=1;i<n;i++) { int k=0,idx=999999999; for(int j=1;j<=n;j++) if(vis[j]==0&&minn[j]<idx) { k=j; idx=minn[j]; } if(k==0) break; vis[k]=1; for(int j=1;j<=n;j++) if(minn[k]+f[k][j]<minn[j]) minn[j]=minn[k]+f[k][j]; } printf("%d\n",minn[t]); }
3.Dijkstra堆优化
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; #define inf 0x3f3f3f3f int t,c,ts,te,to[12401],head[12401],nxt[12401],idx,len[12401],minn[3001]; bool vis[3001]; priority_queue < pair < int , int > , vector < pair < int , int > > , greater < pair < int , int > > > q; void addedge(int a,int b,int c) { to[++idx]=b; len[idx]=c; nxt[idx]=head[a]; head[a]=idx; } int main() { scanf("%d%d%d%d",&t,&c,&ts,&te); for(int i=1;i<=c;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); addedge(b,a,c); } memset(minn,inf,sizeof(minn)); minn[ts]=0; q.push(make_pair(0,ts)); while(!q.empty()) { int p=q.top().second; q.pop(); if(vis[p]) continue; vis[p]=1; for(int i=head[p];i;i=nxt[i]) { if(minn[to[i]]>minn[p]+len[i]) { minn[to[i]]=minn[p]+len[i]; q.push(make_pair(minn[to[i]],to[i])); } } } printf("%d",minn[te]); return 0; }
4.Spfa算法及判负环(以洛谷模板为例)
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<cmath> using namespace std; int n,m,t,head[100001],idx,dis[100001],cnt[100001],to[100001],nxt[100001],len[100001]; bool vis[100001]; void addedge(int x,int y,int z) { to[++idx]=y; nxt[idx]=head[x]; len[idx]=z; head[x]=idx; } bool spfa(int s) { memset(vis,0,sizeof(vis)); memset(dis,0x3f3f3f3f,sizeof(dis)); memset(cnt,0,sizeof(cnt)); queue < int > q; q.push(s); vis[s]=1; dis[s]=0; while(!q.empty()) { int p=q.front(); q.pop(); vis[p]=0; for(int i=head[p];i;i=nxt[i]) { if(dis[to[i]]>dis[p]+len[i]) { dis[to[i]]=dis[p]+len[i]; if(!vis[to[i]]) { q.push(to[i]); vis[to[i]]=1; cnt[to[i]]++; if(cnt[to[i]]>=n)//判负环部分,若一个点入队大于n次,则它一定在一个环内 return 1; } } } } return 0; } int main() { scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); idx=0; memset(head,0,sizeof(head)); for(int i=1,u,v,w;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); if(w<0) addedge(u,v,w); else { addedge(u,v,w); addedge(v,u,w); } } if(spfa(1)==1) printf("YE5\n"); else printf("N0\n"); } }
七.离散化
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<vector> using namespace std; int a[10001],b[10001],n,idx; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[++idx]=a[i]; } sort(b+1,b+idx+1); idx=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+idx+1,a[i])-b; }
八.tarjan缩点
int z[100001],dep[100001],low[100001],top,ans,cnt,neww[100001],f[100001]; bool inz[100001]; void tarjan(int x) { inz[x]=1; vis[x]=1; dep[x]=low[x]=++cnt; z[++top]=x; for(int i=head[x];i;i=nxt[i]) { if(dep[to[i]]==0) { tarjan(to[i]); low[x]=min(low[x],low[to[i]]); } else if(inz[to[i]]!=0) low[x]=min(low[x],dep[to[i]]); } if(dep[x]==low[x]) { ans++; int t; do { t=z[top--]; neww[ans]++; f[t]=ans; inz[t]=0; }while(t!=x); } }
九.KMP算法(以洛谷模板为例)
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; int nxt[1000001],k,ans[1000001],cnt,l1,l2; char s1[1000001],s2[1000001]; void getnxt() { for(int i=2;i<=l2;i++) { while(k!=0&&s2[i]!=s2[k+1]) k=nxt[k]; if(s2[i]==s2[k+1]) k++; nxt[i]=k; } } void KMP() { for(int i=1;i<=l1;i++) { while(k!=0&&s1[i]!=s2[k+1]) k=nxt[k]; if(s1[i]==s2[k+1]) k++; if(k==l2) ans[++cnt]=i-l2+1; } } int main() { scanf("%s%s",s1+1,s2+1); l1=strlen(s1+1); l2=strlen(s2+1); nxt[1]=0; getnxt(); k=0; KMP(); for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]); for(int i=1;i<=l2;i++) printf("%d ",nxt[i]); }
十.高斯消元法
#include<stdio.h> #include<math.h> #define eps 1e-8 int n; double a[105][105],idx2; int main() { scanf("%d",&n); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) scanf("%lf",&a[i][j]); scanf("%lf",&a[i][n]); } for(int i=0;i<n;i++) { int idx=i; for(int j=i;j<n;j++) if(fabs(a[j][i]-a[idx][i])<=eps) idx=j; for(int j=0;j<=n;j++) { idx2=a[i][j]; a[i][j]=a[idx][j]; a[idx][j]=idx2; } if(fabs(a[i][i])<=eps) { printf("No Solution"); return 0; } for(int j=i+1;j<=n;j++) a[i][j]/=a[i][i]; for(int j=0;j<n;j++) if(i!=j) for(int k=i+1;k<=n;k++) a[j][k]-=a[j][i]*a[i][k]; } for(int i=0;i<n;i++) printf("%.2lf\n",a[i][n]); }