您的位置:首页 > 理论基础 > 数据结构算法

NOIP复赛知识点复习:算法/数据结构模板

2017-10-17 13:04 309 查看

如有错误请及时指出~

(纯手打,持续更新中……)

目录:

编号算法/数据结构
0对拍程序
1邻接表
2LCA
3SPFA
4线性筛
5快速幂
6读入优化
7二分(求上/下界)
8并查集
9线段树
10二分图匹配
11网络流
12树状数组
(施工中)

0.对拍程序

转自http://blog.csdn.net/wlx65003/article/details/51149196

@echo off
:loop
rand.exe > in.txt
my.exe < in.txt > myout.txt
std.exe < in.txt > stdout.txt
fc myout.txt stdout.txt
if not errorlevel 1 goto loop
pause
goto loop


1.邻接表

难度:2

有很多种写法,强烈安利我的这种写法,操作简单、便捷。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100050
#define add(u,v,vv) to[++top]=head[u],head[u]=top,w[top]=v,val[top]=vv
#define For(x) for(int h=head[x],o=w[h],v=val[h];h;o=w[h=to[h]],v=val[h])
using namespace std;
int n,m,i,top=0,head[maxn*2],to[maxn*2],w[maxn*2],val[maxn*2],u,v,vv;
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++) scanf("%d%d%d",&u,&v,&vv),add(u,v,vv);
for (i=1;i<=n;i++) For(i) printf("%d to %d:%d\n",i,o,v);
}


2.LCA(最近公共祖先)

难度:2.5

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100050
#define add(u,v) to[++top]=head[u],head[u]=top,w[top]=v
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
using namespace std;
int n,q,u,v,i,top=0,f[maxn][25],d[maxn],head[maxn*2],to[maxn*2],w[maxn*2];
inline void dfs(int x,int fa)
{
d[x]=d[fa]+1;
for (i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
For(x) if (o!=fa) f[o][0]=x,dfs(o,x);
}
inline int lca(int u,int v)
{
if (d[u]<d[v]) swap(u,v);
for (int i=20;i>=0;i--)
{
if (d[f[u][i]]>=d[v]) u=f[u][i];
if (u==v) return u;
}
for (int i=20;i>=0;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][0];
}
int main()
{
scanf("%d%d",&n,&q);
for (i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
dfs(1,0);
while (q--) scanf("%d%d",&u,&v),printf("%d",lca(u,v));
}


3.SPFA

难度:3

队列优化的bfs,时间复杂度O(km)(k约等于2)。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100050
#define add(u,v,vv) to[++top]=head[u],head[u]=top,w[top]=v,val[top]=vv
#define For(x) for(int h=head[x],o=w[h],v=val[h];h;o=w[h=to[h]],v=val[h])
using namespace std;
int top=0,l,r,q[maxn*2],dis[maxn],bo[maxn],head[maxn],to[maxn],w[maxn],val[maxn],n,m,u,v,vv,s,t,x;
inline void spfa()
{
q[l=r=0]=s,memset(bo,0,sizeof(bo)),memset(dis,0x7f,sizeof(dis)),dis[s]=0,bo[s]=1;
while (l<=r)
{
x=q[l];
For(x) if (dis[x]+v<dis[o])
{
dis[o]=dis[x]+v;
if (!bo[o]) bo[o]=1,q[++r]=o;
}
l++,bo[x]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);
while (m--) scanf("%d%d%d",&u,&v,&vv),add(u,v,vv);
scanf("%d%d",&s,&t),spfa(),printf("%d",dis[t]);
}


4.线性筛

难度:2.5

时间复杂度仅为O(n)。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10000050
using namespace std;
int f[maxn],p[maxn],top=0,i,j,n;
int main()
{
scanf("%d",&n),f[0]=f[1]=1,p[0]=0;
for (i=2;i<=n;i++)
{
if (f[i]==0) p[++top]=i;
for (j=1;j<=top&&i*p[j]<=n;j++)
{
f[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
printf("%d\n",top);
for (i=1;i<=top;i++) printf("%d ",p[i]);
}


5.快速幂

难度:2.5

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll x,y,m;
ll qsm(ll x,ll y,ll m)
{
ll ret=1;
x%=m;
while (y)
{
if (y&1) ret*=x;
ret%=m,x*=x,x%=m,y/=2;
}
return ret;
}
int main()
{
scanf("%lld%lld%lld",&x,&y,&m),printf("%lld",qsm(x,y,m));
}


6.读入优化

难度:2,必备技巧

inline void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while (!isdigit(ch))
{
if (ch=='-') f=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}


7.二分

难度:2

推荐两个函数:lower_bound&upper_bound(具体用法不再解释)

对于线性递增的数组,x值的位置下界为lower_bound(a+1,a+n+1,x)-a,上界为upper_bound(a+1,a+n+1,x)-a-1;

求下界:

void binary_find()
{
l=1,r=INF;
while (l!=r)
{
int mid=(l+r)/2;
if (check(mid)) r=mid;else l=mid+1;
}
}


求上界:(注意细节)

void binary_find()
{
l=1,r=INF;
while (l!=r)
{
int mid=(l+r+1)/2;
if (check(mid)) l=mid;else r=mid-1;
}
}


8.并查集

不带权的版本,难度:2

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10050
using namespace std;
int f[maxn],n,m,u,v,opt;
inline int find(int x)
{
if (x==f[x]) return x;
f[x]=find(f[x]); return f[x];
}
inline void union_(int u,int v) {f[find(u)]=find(v);}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) f[i]=i;
while (m--)
{
scanf("%d%d%d",&opt,&u,&v);
if (opt==1) union_(u,v);
else if (find(u)==find(v)) printf("Y\n");else printf("N\n");
}
}


9.线段树(区间加/乘,求和模板)

难度:4

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define maxn 100050
using namespace std;
typedef long long ll;
int a[maxn],ql,qr,val,opt,n,m,p;
struct segment_tree
{
ll t[maxn*4],lz1[maxn*4],lz2[maxn*4];
inline void pushup(int x) {t[x]=t[x*2]+t[x*2+1];}
inline void pushdown(int x,int l,int r)
{
if (lz1[x]==1&&lz2[x]==0) return;
if (lz1[x]!=1)
{
lz1[x*2]=(lz1[x]*lz1[x*2])%p;
lz1[x*2+1]=(lz1[x]*lz1[x*2+1])%p;
lz2[x*2]=(lz1[x]*lz2[x*2])%p;
lz2[x*2+1]=(lz1[x]*lz2[x*2+1])%p;
t[x*2]=(t[x*2]*lz1[x])%p;
t[x*2+1]=(t[x*2+1]*lz1[x])%p;
lz1[x]=1;
}
int mid=(l+r)/2;
if (lz2[x]!=0)
{
lz2[x*2]=(lz2[x*2]+lz2[x])%p;
lz2[x*2+1]=(lz2[x*2+1]+lz2[x])%p;
t[x*2]=(t[x*2]+(mid-l+1)*lz2[x])%p;
t[x*2+1]=(t[x*2+1]+(r-mid)*lz2[x])%p;
lz2[x]=0;
}
}
inline void build(int x,int l,int r)
{
if (l==r) {t[x]=a[l],lz1[x]=1;return;}
int mid=(l+r)/2;
build(x*2,l,mid),build(x*2+1,mid+1,r),pushup(x),lz1[x]=1;
}
inline void upd(int x,int l,int r,int ql,int qr,int val,int k) //k=1:*  k=2:+
{
if (l==ql&&r==qr)
{
if (k==1) lz1[x]=(lz1[x]*val)%p,lz2[x]=(lz2[x]*val)%p,t[x]=(t[x]*val)%p;
if (k==2) lz2[x]=lz2[x]+val,t[x]=(t[x]+val*(r-l+1))%p;
return;
}
pushdown(x,l,r);
int mid=(l+r)/2;
if (qr<=mid) upd(x*2,l,mid,ql,qr,val,k);
else if (ql>mid) upd(x*2+1,mid+1,r,ql,qr,val,k);
else upd(x*2,l,mid,ql,mid,val,k),upd(x*2+1,mid+1,r,mid+1,qr,val,k);
pushup(x);
}
inline ll query(int x,int l,int r,int ql,int qr)
{
if (l==ql&&r==qr) {return t[x]%p;}
pushdown(x,l,r),pushup(x);
int mid=(l+r)/2;
if (qr<=mid) return query(x*2,l,mid,ql,qr)%p;
else if (ql>mid) return query(x*2+1,mid+1,r,ql,qr)%p;
else return (query(x*2,l,mid,ql,mid)+query(x*2+1,mid+1,r,mid+1,qr))%p;
}
}s;
inline void rd(int &x)
{
x=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-48,ch=getchar();
}
int main()
{
rd(n),rd(m),rd(p);
for (int i=1;i<=n;i++) rd(a[i]);
s.build(1,1,n);
while (m--)
{
rd(opt);
if (opt==1) rd(ql),rd(qr),rd(val),s.upd(1,1,n,ql,qr,val,1);
if (opt==2) rd(ql),rd(qr),rd(val),s.upd(1,1,n,ql,qr,val,2);
if (opt==3) rd(ql),rd(qr),printf("%lld\n",s.query(1,1,n,ql,qr));
}
}


10。二分图匹配

难度:3.5

#include<cstdio>
#include<algorithm>
#include<cstring>
#define add(u,v) to[++top]=head[u],head[u]=top,w[top]=v
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
#define maxn 5050
using namespace std;
int top=0,to[maxn*maxn],head[maxn*maxn],w[maxn*maxn],t[maxn],vis[maxn],ans=0,n,m,e,u,v;
inline bool dfs(int x)
{
For(x) if (!vis[o])
{
vis[o]=1;
if (!t[o]||dfs(o)) {t[o]=x; return 1;}
}
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
while (e--)
{
scanf("%d%d",&u,&v);
if (u<=n&&v<=m) add(u,v);
}
for (int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if (dfs(i)) ans++;
}
printf("%d",ans);
}


11.网络流

难度:4

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10050
#define maxm 100050
#define INF 1000000000
#define add(u,v,vv) to[++top]=head[u],head[u]=top,w[top]=v,cap[top]=vv
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
using namespace std;
int top=1,to[maxm*2],head[maxm*2],w[maxm*2],cap[maxm*2],level[maxn],q[maxn*8],l,r,s,t,x;
int n,m,u,v,vv;
inline bool bfs()
{
memset(level,0,sizeof(level));
q[l=r=0]=s,level[s]=1;
while (l<=r)
{
x=q[l++];
For(x) if (cap[h]&&level[o]==0) level[o]=level[x]+1,q[++r]=o;
}
return level[t];
}
inline int dfs(int x,int maxflow)
{
if (x==t||!maxflow) return maxflow;
int ret=0;
For(x) if (cap[h]&&level[o]==level[x]+1)
{
int tmp=dfs(o,min(cap[h],maxflow));
ret+=tmp,maxflow-=tmp,cap[h]-=tmp,cap[h^1]+=tmp;
}
if (!ret) level[x]=0;
return ret;
}
inline int dinic()
{
int ret=0;
while (bfs())
ret+=dfs(s,INF);
return ret;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for (int i=1;i<=m;i++) scanf("%d%d%d",&u,&v,&vv),add(u,v,vv),add(v,u,0);
printf("%d",dinic());
}


12.树状数组

难度:3

我不会同时区间加/求和~

单点加/区间求和:(l到r和为query(r)-query(l-1))

区间加/单点询问:(l到r加x:add(l,x),add(r+1,-x))

inline void add(int x,int y) {while (x<=n) t[x]+=y,x+=lowbit(x);}
inline int query(int x)
{
int ret=0;
while (x>=1) ret+=t[x],x-=lowbit(x);
return ret;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: