先占个坑
[update]NOIp结束了,已弃 PS:貌似只整理了图论和一点数据结构......
一、图论
1.单源最短路
(1)spfa
已加SLF优化 419ms
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=1e4+5,M=5e5+5,INF=2147483647; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,s,u,v,w; struct edge{ int v,ne,w; }e[M<<1]; int h[N],cnt=0; inline void ins(int u,int v,int w){ cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; } inline void lop(int &x){if(x==N) x=1;else if(x==0) x=N-1;} int d[N],q[N],head,tail,inq[N]; void spfa(int s){ for(int i=1;i<=n;i++) d[i]=INF; head=tail=1; q[tail++]=s;inq[s]=1;d[s]=0; while(head!=tail){ int u=q[head++];inq[u]=0;lop(head); for(int i=h[u];i;i=e[i].ne){ int v=e[i].v,w=e[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; if(!inq[v]){ if(d[v]<d[q[head]]) head--,lop(head),q[head]=v; else q[tail++]=v,lop(tail); inq[v]=1; } } } } } int main(){ n=read();m=read();s=read(); for(int i=1;i<=m;i++){u=read();v=read();w=read();ins(u,v,w);} spfa(s); for(int i=1;i<=n;i++) printf("%d ",d[i]); }
(2)dijkstra 503ms
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int N=1e4+5,M=5e5+5,INF=2147483647; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x; } int n,m,s,u,v,w; struct edge{ int v,ne,w; }e[M]; int h[N],cnt=0; inline void ins(int u,int v,int w){ cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; } struct hn{ int u,d; hn(int a=0,int b=0):u(a),d(b){} bool operator <(const hn &r)const{return d>r.d;} }; priority_queue<hn> q; int d[N],done[N]; void dij(int s){ for(int i=1;i<=n;i++) d[i]=INF; d[s]=0; q.push(hn(s,0)); while(!q.empty()){ hn x=q.top();q.pop(); int u=x.u;if(done[u]) continue; done[u]=1; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v,w=e[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; if(!done[v]) q.push(hn(v,d[v]));//xiao you hua } } } } int main(){ n=read();m=read();s=read(); for(int i=1;i<=m;i++){u=read();v=read();w=read();ins(u,v,w);} dij(s); for(int i=1;i<=n;i++) printf("%d ",d[i]); }
(3)dijkstra+配对堆 380ms 吊打用SLF优化的spfa啊啊啊啊啊 [2017-01-14]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <ext/pb_ds/priority_queue.hpp> #define pa pair<int,int> #define mp make_pair using namespace std; using namespace __gnu_pbds; typedef __gnu_pbds::priority_queue<pa,greater<pa>,thin > heap; const int N=1e4+5,M=5e5+5,INF=2147483647; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,s,u,v,w; struct edge{ int v,ne,w; }e[M]; int h[N],cnt=0; inline void ins(int u,int v,int w){ cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; } heap q; heap::point_iterator it[N]; int d[N]; void dij(int s){ for(int i=1;i<=n;i++) d[i]=INF; d[s]=0; it[s]=q.push(mp(0,s)); while(!q.empty()){ int u=q.top().second;q.pop(); for(int i=h[u];i;i=e[i].ne){ int v=e[i].v,w=e[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; if(it[v]!=0) q.modify(it[v],mp(d[v],v)); else it[v]=q.push(mp(d[v],v)); } } } } int main(){ n=read();m=read();s=read(); for(int i=1;i<=m;i++){u=read();v=read();w=read();ins(u,v,w);} dij(s); for(int i=1;i<=n;i++) printf("%d ",d[i]); }
2.判负环
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=1e3+5,M=1e5+5,INF=1e9+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,s,u,v,w; struct edge{ int v,ne,w; }e[M+N]; int h[N],cnt=0; inline void ins(int u,int v,int w){ cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; } inline void lop(int &x){x++;if(x==N) x=1;} int q[N],head=1,tail=1,inq[N]; int d[N],nc[N]; bool spfa(int s){ head=tail=1; for(int i=1;i<=n;i++) d[i]=INF,inq[i]=nc[i]=0; q[tail]=s;inq[s]=nc[s]=1; lop(tail); d[s]=0; while(head!=tail){ int u=q[head];inq[u]=0; lop(head); for(int i=h[u];i;i=e[i].ne){ int v=e[i].v,w=e[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; if(!inq[v]){ inq[v]=1;q[tail]=v; lop(tail); if(++nc[v]>n) return false; } } } } return true; } int main(){ n=read();m=read();s=read(); for(int i=1;i<=m;i++){ u=read();v=read();w=read(); if(u==v&&w<0) {printf("-1");return 0;} if(u!=v)ins(u,v,w); } int ss=n+1;//超级源 for(int i=1;i<=n;i++) ins(ss,i,0); int flag=spfa(ss); if(!flag){printf("-1");return 0;} spfa(s); for(int i=1;i<=n;i++){ if(d[i]>=INF) printf("NoPath\n"); else printf("%d\n",d[i]); } }
3.最小生成树
kruskal
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=5005,M=2e5+5,INF=1e9+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,u,v,w; int cnt=0; struct edge{ int u,v,w; bool operator <(const edge &r)const{return w<r.w;} }e[M]; int fa[N]; inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} int kruskal(){ int ans=0,cnt=0; for(int i=1;i<=n;i++) fa[i]=i; sort(e+1,e+1+m); for(int i=1;i<=m;i++){ int u=e[i].u,v=e[i].v,w=e[i].w; int f1=find(u),f2=find(v); if(f1!=f2){ ans+=w; fa[f1]=f2; cnt++; if(cnt==n-1) break; } } return ans; } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ e[i].u=read();e[i].v=read();e[i].w=read(); } int ans=kruskal(); printf("%d",ans); }
4.floyd
(1)传递闭包
d[i][j]=d[i][j]||(d[i][k]&&d[k][j])
(2)最小环
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=105,M=1e4+5,INF=1e8+5;//1E9+1E9+1E9溢出 inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,u,v,w,g[N][N]; int d[N][N],ans=INF; void floyd(){ ans=INF; for(int k=1;k<=n;k++){ for(int i=1;i<=k-1;i++) for(int j=i+1;j<=k-1;j++) ans=min(ans,g[i][k]+g[k][j]+d[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d[i][j]=min(d[i][j],d[i][k]+d[k][j]); } } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) d[i][j]=d[j][i]=g[i][j]=g[j][i]=INF; for(int i=1;i<=m;i++){ u=read();v=read();w=read(); d[u][v]=d[v][u]=g[u][v]=g[v][u]=w; } floyd(); if(ans==INF) puts("No solution."); else printf("%d\n",ans); } }
5.割点
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=1e5+5,M=1e5+5,INF=1e9+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x; } int n=0,m,u,v; struct edge{ int v,ne; }e[M<<1]; int h[N],cnt=0; inline void ins(int u,int v){ cnt++; e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt; } int dfn[N],low[N],dfc=0,iscut[N]; void dfs(int u,int fa){ dfn[u]=low[u]=++dfc; int child=0; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!dfn[v]){ child++; dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) iscut[u]=1; }else if(v!=fa) low[u]=min(low[u],dfn[v]); } if(fa==0&&child==1) iscut[u]=0; } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){u=read();v=read();ins(u,v);} for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,0); int ans=0; for(int i=1;i<=n;i++) if(iscut[i]) ans++; printf("%d\n",ans); for(int i=1;i<=n;i++) if(iscut[i]) printf("%d ",i); }
6.tarjan 强连通分量
POJ2186
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N=1e4+5,M=5e4+5; typedef long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,u,v; struct edge{ int v,ne; }e[M]; int h[N],cnt=0; inline void ins(int u,int v){ cnt++; e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt; } int dfn[N],belong[N],low[N],dfc,scc,st[N],top; int size[N]; void dfs(int u){ dfn[u]=low[u]=++dfc; st[++top]=u; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!dfn[v]){ dfs(v); low[u]=min(low[u],low[v]); }else if(!belong[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ scc++; while(true){ int x=st[top--]; belong[x]=scc; size[scc]++; if(x==u) break; } } } int outd[N],ind[N],ans; void point(){ for(int u=1;u<=n;u++) for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(belong[u]!=belong[v]) outd[belong[u]]++,ind[belong[v]]++; } } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){u=read();v=read();ins(u,v);} for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); point(); for(int i=1;i<=scc;i++){ if(outd[i]==0){ if(ans){ans=0;break;} else ans=size[i]; } } printf("%d",ans); }
7.二分图染色
bool color(int u,int c){ col[u]=c; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(col[u]==col[v]) return false; if(!col[v]&&!color(v,3-c)) return false; } return true; }
8.二分图最大匹配
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=1005; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,s,u,v; struct edge{ int v,ne; }e[N*N<<1]; int h[N],cnt=0; inline void ins(int u,int v){ cnt++; e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt; } int vis[N],le[N]; bool find(int u){ for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!vis[v]){ vis[v]=1; if(!le[v]||find(le[v])){ le[v]=u; return true; } } } return false; } int ans=0; void hungary(){ for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(find(i)) ans++; } } int main(){ n=read();m=read();int t=read(); for(int i=1;i<=t;i++){u=read();v=read();if(v>m)continue;ins(u,v);} ans=0; hungary(); printf("%d\n",ans); }
数据结构
1.st表
int a[N],f[N][21]; void init(int n){ for(int i=1;i<=n;i++) f[i][0]=a[i]; for(int j=1;j<=20;j++) for(int i=1;i+(1<<j)-1<=n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); } int RMQ(int l,int r){ int k=log(r-l+1)/log(2); //2^k<=l~r return min(f[l][k],f[r-(1<<k)+1][k]); }
2.trie树
int ch[N*L][27],size=0,val[N*L]; void insert(char s[],int n,int id){ int u=0; for(int i=1;i<=n;i++){ int v=s[i]-'a'; if(!ch[u][v]) ch[u][v]=++size; u=ch[u][v]; } val[u]=id;//printf("ins %d %d\n",u,id); }
3.单调栈
求最大全flag子矩阵
void sol(int flag){ memset(tot,0,sizeof(tot)); for(int i=1;i<=n;i++){ top=0; for(int j=1;j<=m;j++){ if(a[i][j]==flag) tot[j]++; else tot[j]=0; data t; t.h=tot[j];t.l=1;t.pos=j; while(top&&st[top].h>=t.h){ int l=st[top].l+j-1-st[top].pos,h=st[top].h; ans1=max(ans1,min(l,h)*min(l,h)); ans2=max(ans2,l*h); t.l+=st[top].l; top--; } st[++top]=t; } while(top){ int l=st[top].l+m-st[top].pos,h=st[top].h; ans1=max(ans1,min(l,h)*min(l,h)); ans2=max(ans2,l*h); top--; } } }
4.单调队列
q[]保存的是下标
删除 while(head<=tail&&q[head]<=i-k) head++; //也可能<
插入 while(head<=tail&&a[q[tail]]>a[i]) tail--;//单增 q[++tail]=i;
5.并查集
带权
for(int i=1;i<=n;i++) fa[i]=i,d[i]=0,s[i]=1; int fa[N],d[N],s[N]; inline int find(int x){ if(x==fa[x]) return x; int root=find(fa[x]); d[x]+=d[fa[x]]; return fa[x]=root; }
6.树状数组
7.线段树