常用baozi

快读,不解释(也有一种(x<<3)+(x<<1)的写法,一样的)

int read()
{
    int x=0,b=1;char c=getchar();
    while(!isdigit(c)) b=c=='-'?-1:1,c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x*b;
}
View Code

数组实现线段树(不解释,注意细节不要写错就可)

#include <stdio.h>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn=200000;
int sum[maxn],a[maxn],add[maxn];
int n;

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
void ADD(int k,int l,int r,int v)
{
    add[k]+=v;
    sum[k]+=(r-l+1)*v;
}
void pushdown(int k,int l,int r,int mid)
{
    if(add[k]==0) return;
    ADD(k<<1,l,mid,add[k]);
    ADD(k<<1|1,mid+1,r,add[k]);
    add[k]=0;
}
void change(int k,int l,int r,int x,int y,int v)
{
    if(l>=x&&r<=y)
    {
        ADD(k,l,r,v);
        return;
    }
    int mid=l+r>>1;
    pushdown(k,l,r,mid);
    if(mid>=x) change(k<<1,l,mid,x,y,v);
    if(mid<y) change(k<<1|1,mid+1,r,x,y,v);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
int query(int k,int l,int r,int x,int y)
{
    if(l>=x&&r<=y) return sum[k];
    int mid=l+r>>1;
    pushdown(k,l,r,mid);
    int res=0;
    if(mid>=x)res+=query(k<<1,l,mid,x,y);
    if(mid<y) res+=query(k<<1|1,mid+1,r,x,y);
    return res;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    while(1)
    {
        int k;scanf("%d",&k);
        if(k==1)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%d",query(1,1,n,a,b));
        }
        else
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            change(1,1,n,a,b,c);
        }
    }
    return 0;
}
View Code

 扩展GCD

int ecgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1,y=0;
    }
    else exgcd(b,a%b,y,x) y-=a/b*x;
}
x=(x+p)%p
View Code

堆优化的prime算法

#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

const int maxn=400020;//注意无向图要开两倍的大小
int head[maxn],nex[maxn],ver[maxn],wei[maxn],tot;
bool vis[maxn];
int dis[maxn],cnt;
int n,m,sum;
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii> > q;
void add(int x,int y,int w)
{
    ver[++tot]=y;
    wei[tot]=w;
    nex[tot]=head[x];
    head[x]=tot;
}
void prime()
{
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    q.push(make_pair(0,1));//注意这里插入的时候是make_pair(0,1)
    while(q.size()&&cnt<n)
    {
        pii t=q.top();q.pop();
        int x=t.second,d=t.first;
        if(vis[x]) continue;
        cnt++;
        sum+=d;//这里d数组存储的就仅仅只是每一个点到外面的最短边的距离了
        vis[x]=1;
        for(int i=head[x];i;i=nex[i])
        {
            int y=ver[i];
            if(dis[y]>wei[i])
            {
                dis[y]=wei[i];
                q.push(make_pair(dis[y],y));
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    prime();
    if(cnt==n) printf("%d",sum);
    else printf("orz");
    return 0;
}

树链剖分+区间修改线段树

#include <stdio.h>
#include <algorithm>
#include <cstring>
#define lson (k<<1)
#define rson (k<<1|1)
#define mid ((l+r)>>1)

using namespace std;

const int maxn=100020;

int s[maxn<<1],tag[maxn<<1];
int n,m,rt,p;
int dep[maxn],sz[maxn],fa[maxn],son[maxn];
int rev[maxn],id[maxn],idx,top[maxn];
int a[maxn];
int head[maxn<<1],nex[maxn<<1],ver[maxn<<!1],tot;

void add(int x,int y)
{
    ver[++tot]=y;
    nex[tot]=head[x];
    head[x]=tot;
}
void dfs(int x,int f)
{
    dep[x]=dep[f]+1;fa[x]=f;sz[x]=1;
    for(int i=head[x];i;i=nex[i])
    {
        int y=ver[i];
        if(y==f) continue;
        dfs(y,x);
        sz[x]+=sz[y];
        if(sz[y]>sz[son[x]])son[x]=y;
    }
}
void dfs2(int x,int t)
{
    id[x]=++idx;rev[id[x]]=x;top[x]=t;
    if(!son[x]) return;
    dfs2(son[x],t);
    for(int i=head[x];i;i=nex[i])
    {
        int y=ver[i];
        if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
    }
}
void build(int k,int l,int r)
{
    if(l==r)
    {
        s[k]=a[rev[l]];
        return ;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    s[k]=(s[lson]+s[rson])%p;
}
void pushdown(int k,int l,int r)//1?¡Á¡é?¨¤¨¤? 
{
    if(!tag[k]) return ;
    tag[lson]=(tag[lson]+tag[k])%p;
    tag[rson]=(tag[rson]+tag[k])%p;
    s[lson]=(s[lson]+(mid-l+1)*tag[k])%p;
    s[rson]=(s[rson]+(r-mid)*tag[k])%p;//tag标记的下传要理解,整体区间就不需要下传,否则就更新左右两端点并且下传
    tag[k]=0;
    return ;
    
}
void change(int k,int l,int r,int x,int y,int v)
{
    if(l>y||r<x||l>r) return ;
    if(l>=x&&r<=y)
    {
        tag[k]=(tag[k]+v)%p;
        s[k]=(s[k]+(r-l+1)*v)%p;//注意这里要return 并且长度是(r-l+1)所以一定要注意
        return;
    }
    pushdown(k,l,r);
    if(mid>=x) change(lson,l,mid,x,y,v);
    if(mid<y) change(rson,mid+1,r,x,y,v);
    s[k]=(s[lson]+s[rson])%p;
    return;
}
void update(int x,int y,int z)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        change(1,1,n,id[top[x]],id[x],z);
        x=fa[top[x]];
    }
    if(id[x]>id[y]) swap(x,y);
    change(1,1,n,id[x],id[y],z);
    return ;
}
int query(int k,int l,int r,int x,int y)
{
    if(l>y||r<x||l>r) return 0 ;
    if(l>=x&&r<=y) return s[k];
    pushdown(k,l,r);
    int res=0;
    if(mid>=x) res+=query(lson,l,mid,x,y);
    if(mid<y) res+=query(rson,mid+1,r,x,y);
    res%=p;
    return res;
}
int ask(int x,int y)
{
    int res=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res+=query(1,1,n,id[top[x]],id[x]);
        res%=p;
        x=fa[top[x]];
    }
    if(id[x]>id[y]) swap(x,y);
    res+=query(1,1,n,id[x],id[y]);
    res%=p;
    return res;
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&rt,&p);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(rt,0);dfs2(rt,rt);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int mod;scanf("%d",&mod);
        int x,y,z;
        if(mod==1) scanf("%d%d%d",&x,&y,&z),update(x,y,z);
        if(mod==2) scanf("%d%d",&x,&y),printf("%d\n",ask(x,y));
        if(mod==3) scanf("%d%d",&x,&y),change(1,1,n,id[x],id[x]+sz[x]-1,y);
        if(mod==4) scanf("%d",&x),printf("%d\n",query(1,1,n,id[x],id[x]+sz[x]-1));
    }
    return 0;
}

 kruskal算法:

#include <stdio.h>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn=200020;

struct node
{
    int x,y,wei;
}s[maxn];
int n,m,sum,cnt=0;
int fa[maxn];
int find(int x)
{
      while(x!=fa[x]) x=fa[x]=fa[fa[x]];
    return x;
}
void he(int x,int y)
{
    int t1=find(x),t2=find(y);
    fa[t1]=t2;//注意合并是f[t1]=t2
}
bool bmp(node a,node b)
{
    return a.wei<b.wei;
}
void kru()
{
    for(int i=0;i<m;i++)
    {
        int t1=find(s[i].x),t2=find(s[i].y);
        if(t1==t2) continue;
        else
        {
            he(s[i].x,s[i].y);
            sum+=s[i].wei;
            cnt++;
            if(cnt==n-1) break;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].wei);
    }
    sort(s,s+m,bmp);
    kru();
    printf("%d",sum);
    return 0;
}

 桥的求法:

#include <stdio.h>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn=5020,maxm=20020;
int head[maxn],nex[maxm],ver[maxm],tot;
int dcnt,id[maxn];
int du[maxn];
int low[maxn],dfn[maxn],idx,sta[maxn],top;
bool bri[maxm];
int n,m;
void trajan(int x,int from)//from存储的是从哪一条边过来的
{
   // printf("%d %d \n",x,from);
    low[x]=dfn[x]=++idx;
    sta[++top]=x;
    for(int i=head[x];~i;i=nex[i])//如果要使用从0开始的tot的话 那么就要用~i防止爆炸,并且之前额head需要重置成-1
    {
       // printf("%d %d\n",x,ver[i]);
        int y=ver[i];
        if(!dfn[y])
        {
            trajan(y,i);
            low[x]=min(low[x],low[y]);
            if(dfn[x]<low[y])//判断条件,y永远到达不了x,那么x->y和反向边就是了
            bri[i]=bri[i^1]=true;
        }
        else if(i!=(from^1))
        {
            low[x]=min(low[x],dfn[y]);//如果不是反向边,那么就是后箱边,所以就可以直接更新(环就出现了)
        }
    }
    if(dfn[x]==low[x])
    {
        dcnt++;id[x]=dcnt;//这种写法要先把x加入,但是do while就不需要了
        while(sta[top]!=x)
        {
            id[sta[top]]=dcnt;
            top--;
        }
        top--;
    }
}
void add(int x,int y)
{
    ver[tot]=y;
    nex[tot]=head[x];
    head[x]=tot++;
}
int main()
{
    memset(head,-1,sizeof head);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    //for(int i=head[1];~i;i=nex[i]) printf("%d ",ver[i]);
    trajan(1,-1);
    for(int i=0;i<tot;i++)
    {
        if(bri[i])
        du[id[ver[i]]]++;
    }
    //for(int i=1;i<=n;i++) printf("%d ",id[i]);
    int ans=0;
    for(int i=1;i<=dcnt;i++)
    {
        if(du[i]==1) ans++;
    }
    //printf("%d \n",ans);
    printf("%d",(ans+1)/2);
    return 0;
}

 组合数的相关求法:

1.a,b较小,并且询问较多时

void init()
{
    for(int i=0;i<maxn;i++)
        for(int j=0;j<=i;j++)
        if(!j) c[i][j]=1;
        else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}

 字符串算法:kmp

#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=20000;
int p[maxn],k,n,m,ans;
char a[1000],b[1000];
void pre()
{
    int i,j;
    p[1]=0;
    j=0;//
    for(i=1;i<m;i++)//ÕâÀïµÄÑ­»·´Ó1¿ªÊ¼£¬ÒòΪp[1]=0 
    {
        while (j>0&&b[i+1]!=b[j+1]) j=p[j];
        if(b[i+1]==b[j+1]) j++;
        p[i+1]=j;
    }
}
int main()
{
    int i,j;
    scanf("%d",&k);
    while(k--)
    {
        scanf("%s",a+1);
        scanf("%s",b+1);
        n=strlen(a+1);m=strlen(b+1);
        pre();
        j=0;ans=0;//ÿ´Î´¦Àí¶¼ÐèÒªÏë×ųõʼ»¯£¨»òÕßÖØÉ裩 
        for(i=0;i<n;i++)
        {
            while (j>0&&a[i+1]!=b[j+1]) j=p[j];
            if(a[i+1]==b[j+1]) j++;
            if(j==m)//ÕâÀïÊÇѰÕÒÖØ¸´ÏҪ²»È»¾ÍÐèÒªÈÃj=P[J] 
            {
                ans++;
                j=0;
            }
        }
        printf("%d",ans);
    }
    return 0;
}
View Code

 

posted @ 2020-08-29 09:22  ILH  阅读(215)  评论(0)    收藏  举报