NOIP 模板整理(多图预警╮(╯▽╰)╭)

马上就要考NOIP了,是时候整理一下模板了233

线段树模板

区间修改+区间求和

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
long long xl[233333];
struct jgt
{
    int l,r;
    long long sum,add;
}hah[233333*4];
void build(int p,int l,int r)
{
    hah[p].l=l;
    hah[p].r=r;
    if(l==r)
    {
        hah[p].sum=xl[l];
        return ;
    }
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    hah[p].sum=hah[p*2].sum+hah[p*2+1].sum;
}
void spread(int p)
{
    if(hah[p].add)
    {
        hah[p*2].sum+=(hah[p*2].r-hah[p*2].l+1)*hah[p].add;
        hah[p*2+1].sum+=(hah[p*2+1].r-hah[p*2+1].l+1)*hah[p].add;
        hah[p*2].add+=hah[p].add;
        hah[p*2+1].add+=hah[p].add;
        hah[p].add=0;
    }
}
long long ask(int p,int l,int r)
{
    if(l<=hah[p].l&&hah[p].r<=r)
    {
        return hah[p].sum;
    }
    spread(p);
    long long ans=0;
    int mid=(hah[p].l+hah[p].r)/2;
    if(l<=mid) ans+=ask(p*2,l,r);
    if(mid<r) ans+=ask(p*2+1,l,r);
    return ans;
}
void change(int p,int l,int r,long long x)
{
    if(l<=hah[p].l&&hah[p].r<=r)
    {
        hah[p].sum+=(hah[p].r-hah[p].l+1)*x;
        hah[p].add+=x;
        return ;
    }
    spread(p);
    int mid=(hah[p].l+hah[p].r)/2;
    if(l<=mid) change(p*2,l,r,x);
    if(mid<r) change(p*2+1,l,r,x);
    hah[p].sum=hah[p*2].sum+hah[p*2+1].sum;
}
int main()
{
    int n,q;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&xl[i]);
    build(1,1,n);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int u;
        scanf("%d",&u);
        if(u==1)
        {
            int a,b;
            long long x;
            scanf("%d%d%lld",&a,&b,&x);
            change(1,a,b,x);
        }
        if(u==2)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%lld\n",ask(1,a,b));
        }
    }
    return 0;
}

这里写图片描述

询问区间最值

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=233333;
int xl[MAXN];
struct jgt
{
    int l,r,maxx,minn;
}hah[MAXN<<2];
void updata(int p)
{
    hah[p].maxx=max(hah[p<<1].maxx,hah[p<<1|1].maxx);
    hah[p].minn=min(hah[p<<1].minn,hah[p<<1|1].minn);
}
void build(int p,int l,int r)
{
    hah[p].l=l;
    hah[p].r=r;
    if(l==r)
    {
        hah[p].maxx=hah[p].minn=xl[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    updata(p);
}
int askmax(int p,int l,int r)
{
    if(l<=hah[p].l&&hah[p].r<=r)
        return hah[p].maxx;
    int mid=(hah[p].l+hah[p].r)>>1;
    int ans=0;
    if(l<=mid) ans=max(ans,askmax(p<<1,l,r));
    if(mid<r) ans=max(ans,askmax(p<<1|1,l,r));
    return ans;
}
int askmin(int p,int l,int r)
{
    if(l<=hah[p].l&&hah[p].r<=r)
        return hah[p].minn;
    int mid=(hah[p].l+hah[p].r)>>1;
    int ans=233333333;
    if(l<=mid) ans=min(ans,askmin(p<<1,l,r));
    if(mid<r) ans=min(ans,askmin(p<<1|1,l,r));
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&xl[i]);
    build(1,1,n);
    printf("%d %d\n",askmax(1,1,n),askmin(1,1,n));
    return 0;
}

这里写图片描述

最短路模板

spfa(Shortest Path Faster Algorithm强行装逼╮(╯▽╰)╭):

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct edge
{
    int from,to,cost;
}es[MAXE<<1];
void init()
{
    memset(first,-1,sizeof(first));
    memset(d,63,sizeof(d));
    tot=0;
}
void build(int f,int t,int d)
{
    es[++tot]=(edge){f,t,d};
    nxt[tot]=first[f];
    first[f]=tot;
}
queue<int> Q;
void spfa(int s)
{
    d[s]=0;
    Q.push(s);
    used[s]=1;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        used[u]=0;
        for(int i=first[u];i!=-1;i=nxt[i])
        {
            int v=es[i].to;
            if(d[v]>d[u]+es[i].cost)
            {
                d[v]=d[u]+es[i].cost;
                if(!used[v])
                {
                    Q.push(v);
                    used[v]=1;
                    if(++time[v]>n)//判负环 
                    {
                        flag=1;
                        return ;
                    }
                }
            }
        }
    }
}

/*---------------华丽的分割线---------------*/

deque<int> Q;//slf(双端队列优化)
void spfa(int s)
{
    d[s]=0;
    Q.push_front(s);
    used[s]=1;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop_front();
        used[u]=0;
        for(int i=first[u];i!=-1;i=nxt[i])
        {
            int v=es[i].to;
            if(d[v]>d[u]+es[i].cost)
            {
                d[v]=d[u]+es[i].cost;
                if(!used[v])
                {
                    used[v]=1;
                    if(++time[v]>n)//判负环 
                    {
                        flag=1;
                        return ;
                    }
                    if(Q.empty()) Q.push_back(v);
                    else if(d[Q.front()]>d[v]) Q.push_front(v);
                    else Q.push_back(v);
                }
            }
        }
    }
}
int main()
{
    ......
    return 0;
}

这里写图片描述

dijkstra(听说dijkstra能求第k短路所以还是有必要学一下):

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct edge
{
    int from,to,cost;
}es[MAXE<<1];
struct node
{
    int num,dis;
    bool operator < (node b) const
    {
        return dis>b.dis;
    }
};
void init()
{
    memset(first,-1,sizeof(first));
    memset(dis,63,sizeof(dis));
    tot=0;
}
void build(int f,int t,int d)
{
    es[++tot]=(edge){f,t,d};
    nxt[tot]=first[f];
    first[f]=tot;
}
void dijkstra(int s)
{
    d[s]=0;
    while(true)
    {
        int v=-1;
        for(int i=1;i<=n;i++)
            if((v==-1||d[i]<d[v])&&!used[i]) v=i;
        if(v==-1) return ;
        used[v]=1;
        for(int i=first[v];i!=-1;i=nxt[i])
        {
            int u=es[i].to;
            if(d[u]>d[v]+es[i].cost)
                d[u]=d[v]+es[i].cost;
        }
    }
}

/*---------------华丽的分割线---------------*/

priority_queue<node> Q;//加了堆优化
void dijkstra(int s) 
{
    d[s]=0;
    Q.push((node){s,d[s]});
    while(!Q.empty())
    {
        node u=Q.front();
        Q.pop();
        used[u.num]=1;
        for(int i=first[u.num];i!=-1;i=nxt[i])
        {
            int v=es[i].to;
            if(d[v]>u.dis+es[i].cost)
            {
                d[v]=u.dis+es[i].cost;
                if(!used[v]) Q.push((node){v,d[v]});
            }
        }
    }
} 
int main()
{
    ......
    return 0;
}

这里写图片描述

floyd(这是个非常神奇的最短路算法,有很多拓展,然而我不会╮(╯▽╰)╭):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
void floyd
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++) if(k!=i)
            for(int j=1;j<=n;j++) if(i!=j)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
int main()
{
    ......
    return 0;
}

这里写图片描述

并查集模板

并查集:(带路径压缩):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
void init()
{
    for(int i=1;i<=n;i++) fa[i]=i;//初始化 
}
void find(int x,int y)//查询 
{
    return fa[x]==x?x:fa[x]=find(fa[x]);//自带路径压缩╮(╯▽╰)╭ 
} 
void merge(int x,int y)//合并 
{
    int f1=find(x);
    int f2=find(y);
    if(f1!=f2) fa[f1]=f2;
}
int main()
{
    ......
    return 0;
}

这里写图片描述

最小生成树模板

kruskal(适用于稀疏图,听cy学长说能跟01分数规划搞一搞╮(╯▽╰)╭):

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int tot=0;
struct edge
{
    int from,to,cost;
}es[MAXE<<1];
void build(int f,int t,int d)
{
    es[++tot]=(edge){f,t,d};
}
bool cmp(edge a,edge b)
{
    return a.cost<b.cost;
}
void kruskal()
{
    int cnt=0;
    sort(es+1,es+tot+1,cmp);
    for(int i=1;i<=tot;i++)
    {
        int f1=find(es[i].from);
        int f2=find(es[i].to);
        if(f1!=f2)
        {
            fa[f1]=f2;
            ans+=es[i].cost;
            if(++cnt==n-1) break;
        }
    }
}
int main()
{
    ......
    return 0;
}

这里写图片描述

prim(适用于稠密图,据说加了堆优化之后跑的比kruskal快,然并卵╭(╯^╰)╮)

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=0x7fffffff;
int first[30100],nxt[366100];
int n,tot,ans=0,d[30100];
bool vis[30100];
struct edge
{
    int from,to,cost;
}es[366100];
void init()
{
    memset(first,-1,sizeof(first));
    tot=0;
}
void build(int f,int t,int d)
{
    es[++tot]=(edge){f,t,d};
    nxt[tot]=first[f];
    first[f]=tot;
}
void prim()
{
    int u;
    vis[1]=1;
    for(int i=first[1];i!=-1;i=nxt[i])
        d[es[i].to]=es[i].cost;
    for(int i=1;i<=n;i++)
    {
        int minn=inf;
        for(int j=2;j<=n;j++)
        {
            if(vis[j]) continue;
            if(d[j]<minn)
            {
                minn=d[j];
                u=j;
            }
        }
        if(minn==inf) return ;
        ans+=minn;
        vis[u]=1;
        for(int j=first[u];j!=-1;j=nxt[j])
        {
            int v=es[j].to;
            if(!vis[v]&&es[j].cost<d[v])
                d[v]=es[j].cost;
        }
    }
}
int main()
{
    ......
    prim();
    ......
    return 0;
}

这里写图片描述

Tarjan模板

Tarjan求scc(我现在只会这个╮(╯▽╰)╭):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXV=100100;
const int MAXE=100100;
int first[MAXV],nxt[MAXE<<1];
int dfn[MAXV],low[MAXV];
int stack[MAXV],scc[MAXV],size[MAXV],du[MAXV];
int n,m,tot,tot1,snum,cnt;
bool in_stack[MAXV];
struct edge
{
    int from,to;
}es[MAXE<<1];
void init()
{
    memset(first,-1,sizeof(first));
    tot=0;
}
void build(int f,int t)
{
    es[++tot]=(edge){f,t};
    nxt[tot]=first[f];
    first[f]=tot;
}
void group(int u)
{
    dfn[u]=low[u]=++tot1;
    stack[++snum]=u;
    in_stack[u]=1;
    for(int i=first[u];i!=-1;i=nxt[i])
    {
        int v=es[i].to;
        if(!dfn[v])
        {
            group(v);
            low[u]=min(low[u],low[v]);
        }
        else if(in_stack[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        cnt++;
        while(stack[snum+1]!=u)
        {
            scc[stack[snum]]=cnt;
            in_stack[stack[snum]]=0;
            size[cnt]++;
            snum--;
        }
    }
}
int main()
{
    ......
    for(int i=1;i<=n;i++)
        if(!dfn[i]) group(i);
    ......
    return 0;
}

这里写图片描述

拓扑排序模板

拓扑排序(可以找环之类的╮(╯▽╰)╭):

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
struct edge
{
    int from,to,cost;
}es[MAXE<<1];
void init()
{
    memset(first,-1,sizeof(first));
    tot=0;
}
void build(int f,int t,int d)
{
    es[++tot]=(edge){f,t,d};
    nxt[tot]=first[f];
    first[f]=tot;
}
queue<int> Q;
void top_sort()
{
    for(int i=1;i<=n;i++)
        if(!ru[i])
        {
            Q.push(i);
            used[i]=1;
            printf("%d ",i);
        }
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for(int i=first[u];i!=-1;i=nxt[i])
        {
            int v=es[i].to;
            ru[v]--;
            if(!ru[v])
            {
                printf("%d ",v);
                Q.push(v);
                used[v]=1;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        build(a,b);
        ru[b]++;
    }
    top_sort();
    return 0;
}

这里写图片描述

最近公共祖先模板

(倍增)LCA

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct edge
{
    int from,to,cost;
}es[MAXE<<1];
void init()
{
    memset(first,-1,sizeof(first));
    tot=0;
}
void build(int f,int t,int d)
{
    es[++tot]=(edge){f,t,d};
    nxt[tot]=first[f];
    first[f]=tot;
}
void dfs(int s)
{
    used[s]=1;
    for(int i=first[s];i!=-1;i=nxt[i])
    {
        int v=es[i].to;
        if(!used[v])
        {
            deep[v]=deep[s]+1;
            dis[v]=dis[s]+es[i].cost;//dis[v]=es[i].cost; //有多种方法存dis
            fa[v]=s;//fa[v][0]=s; //暴力和倍增的fa数组
            dfs(v);
        }
    }
}
void lca(int x,int y)//暴力lca 
{
    if(deep[x]>deep[y]) swap(x,y);
    while(deep[x]!=deep[y])
    {
        y=fa[y];
    }
    while(x!=y)
    {
        x=fa[x];
        y=fa[y];
    }
    return x;
}

/*---------------华丽的分割线---------------*/

void lca(int x,int y)//倍增lca 
{
    for(int i=0;i<n;i++)
        for(int j=1;j<=20;j++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    if(deep[x]>deep[y]) swap(x,y);
    int tt=deep[y]-deep[x];
    for(int i=0;i<=20;i++)
        if((1<<i)&tt) y=fa[y][i];
    for(int i=20;i>=0;i--)
        if(fa[y][i]!=fa[x][i])
        {
            x=fa[x][i];
            y=fa[y][i];
        }
    if(x!=y) return fa[x][0];
    else return x;

}
int main()
{
    ......
    return 0;
}

这里写图片描述

数论模板

gcd(__gcd)&&lcm:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
int lcm(int a,int b)
{
    return a*b/gcd(a,b);
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d %d\n",gcd(a,b),lcm(a,b));
    return 0;
}

这里写图片描述

埃氏筛法(仅次于线性筛╮(╯▽╰)╭):

#include<cmath> 
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
bool pri[1000100];
int su[1000100];
int main()
{
    int n,tot=0;
    scanf("%d",&n);
    memset(pri,1,sizeof(pri));
    pri[0]=0,pri[1]=0;
    for(int i=2;i<=sqrt(n);i++)
    {
        if(pri[i])
        {
            tot++;
            su[tot]=i;
            for(int j=i*i;j<=n;j+=j) pri[j]=0;
        }
    }
    return 0;
}

这里写图片描述

欧拉筛法(线性筛):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int pri[10100];
bool vis[10100]; 
int main()
{
    int n,cnt=0;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) pri[++cnt]=i;
        for(int j=1;j<=cnt&&i*pri[j]<=n;j++)
        {
            vis[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
    for(int i=1;i<=cnt;i++)
        printf("%d ",pri[i]);
    printf("\n");
    return 0;
}

这里写图片描述

快速幂(非常实用的算法):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
long long ksm(long long x,long long y,long long p)//递归版 
{
    if(y==0) return 1;
    if(y==1) return x%p;
    long long fx=ksm(x,y/2,p);
    if(y%2==0) return (fx%p*fx%p)%p;
    else return ((fx%p*fx%p)%p*x%p);
}

/*---------------华丽的分割线---------------*/

long long ksm2(long long a,long long k,long long p)//二进制版 
{
    long long ans=1;
    for(;k;k>>=1,a=(a%p*a%p)%p)
        if(k&1) ans=(ans%p*a%p)%p;
    return ans%p;
}
int main()
{
    int a,b,p;
    scanf("%d%d%d",&a,&b,&p);
    printf("%lld",ksm(a,b,p));
    return 0;
}

这里写图片描述

其他模板

归并排序求逆序对

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int a[100100],zh[100100];
unsigned long long k=0;
void merge_sort(int l,int r)
{
    if(l>=r) return ;
    int mid=(l+r)/2;
    merge(l,mid);
    merge(mid+1,r);
    int p=l,q=l,j=mid+1;
    while(p<=mid&&j<=r)
    {
        if(a[p]>a[j])
        {
            k+=mid-p+1;
            zh[q++]=a[j++];
        }
        else zh[q++]=a[p++];
    }
    while(p<=mid) zh[q++]=a[p++];
    while(j<=r) zh[q++]=a[j++];
    for(int i=l;i<=r;i++) a[i]=zh[i];
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    merge_sort(1,n);
    cout<<k;
    return 0;
}

这里写图片描述

状态压缩BFS(以codevs解药还是毒药为例):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int bin[100],n,m,sum=0,tot=0;
int yao[110][110];//yao[i][j]表示第i种药对第j种病的影响 
bool used[10100],flag;
struct anti
{
    int sta[110],num;
}hah[10100];//队列 
void init()
{
    for(int i=1;i<=n;i++)
    {
        sum+=1<<i;//sum是最终状态,记录一下最终状态 
        bin[i]=1<<i;//预处理每一位修改需要加上的值 
    }
}
void bfs()
{
    init();//初始化 
    int tt=0,ww=1;
    while(tt<ww)
    {
        tt++;
        for(int i=1;i<=m;i++)
        {
            int tot=0;
            ww++;
            for(int j=1;j<=n;j++)//从队列中取出的元素向下BFS 
            {
                if(yao[i][j]==1) hah[ww].sta[j]=1;//如果能治好 
                else if(yao[i][j]==-1) hah[ww].sta[j]=0;//如果会得病 
                else hah[ww].sta[j]=hah[tt].sta[j];//如果是0就让他不变 
                if(hah[ww].sta[j]) tot+=bin[j];//当前位是一就加上预处理的需要加的数 
            }
            if(!used[tot])//如果当前状态没有搜到过就加入队列 
            {
                used[tot]=1;
                hah[ww].num=hah[tt].num+1;//记录一下用的药的数量 
                if(tot==sum)//搜到最终状态就退出 
                {
                    printf("%d\n",hah[ww].num);
                    flag=1;
                    return ;
                }
            }
            else ww--;//如果已经搜过就不需要加入队列 
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&yao[i][j]);
    bfs();
    if(!flag) printf("The patient will be dead.\n");
    return 0;
}

这里写图片描述

发布了81 篇原创文章 · 获赞 2 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Loi_YZS/article/details/53155439