NOIP的基本模板合集(2)

目录:

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]);    
}

 

posted @ 2018-10-29 09:12  jiangminghong  阅读(360)  评论(0编辑  收藏  举报