NOIP模板整理计划

先占个坑

[update]NOIp结束了,已弃 PS:貌似只整理了图论和一点数据结构......




一、图论

1.单源最短路

洛谷P3371

(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.判负环

Vijos P1053Easy sssp

#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
");
        else printf("%d
",d[i]);
    }
}

3.最小生成树

洛谷P3366

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)最小环

Vijos P1046观光旅行

#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
",ans);
    }
}

5.割点

洛谷P3388 

#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
",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.二分图最大匹配

洛谷P3386

#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
",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
",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.线段树

原文地址:https://www.cnblogs.com/candy99/p/template.html