目录:
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
",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
",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
",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
",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
",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
",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
",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
",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
",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
");
else
printf("N0
");
}
}
七.离散化
#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
",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
",a[i][n]);
}