那么来一波模板吧=。=


ST表(RMQ问题)
//打表与查询 这个是针对最大最小值

    void STpre()
    {
        for(int i = 1; i <= n; i++) dp[i][0][0] = dp[i][0][1] = d[i];

        for(int j = 1; (1<<j) < n; j++)
        for(int i = 1; i <= n; i++)
        {
            if(i + (1<<j) -1 > n) continue;
            dp[i][j][0] = max(dp[i][j-1][0],dp[i+(1<<(j-1))][j-1][0]);
            dp[i][j][1] = min(dp[i][j-1][1],dp[i+(1<<(j-1))][j-1][1]);
        }
    }
    void rmq(int a,int b)
    {
        int len = b-a+1;
        int k = 0;
        while(1<<(k+1) <= len)  k++;
        int la = max(dp[a][k][0],dp[b-(1<<k)+1][k][0]);
        int sm = min(dp[a][k][1],dp[b-(1<<k)+1][k][1]);
    }

LCA(tarjan)

    void tarjan(int u)
    {
        anc[u] = u;
        for(int i = h[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].to;
            if(!vis[v])
            {
                vis[v] = 1;
                tarjan(v);  join(u,v);
                anc[getf(u)] = u;
                vis[v] = 0;
            }
        }
        col[u] = 1;
        for(int i = h1[u]; ~i; i = query[i].next)
        {
            int v = query[i].to, id = query[i].w;
            if(!col[v]) continue;
            ans[id] = d[u] + d[v] - 2*d[anc[getf(v)]];
        }
    }

LCA(倍增)

预处理每个结点的父亲和深度

    void pre(int u,int d,int fa)       //处理每个结点的深度和父亲
    {
        for(int i = h[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].to, w = edge[i].w;
            if(fa != v)
            {
                dis[v] = dis[u] + w;
                dp[v][0] = u;   maxd[v] = d;
                pre(v,d+1,u);
            }
        }
    }    

倍增的预处理

    int doubl()                 //倍增的预处理
    {
        for(int j = 1; j <= 20; j++)
        for(int i = 1; i <= n ; i++)
        {
            if((1 << j) > maxd[i]) continue;
            int k = dp[i][j-1]; dp[i][j] = dp[k][j-1];
        }
        return 0;
    }

询问

    int query(int a,int b)
    {
        int x = a, y = b;
        int ans = 0;
        if(maxd[x] > maxd[y]) swap(x,y);
        for(int j = 20; j >= 0; j--)//先跳到同一高度,再一起往上跳。
        {
            if(maxd[x] == maxd[y]) break;
            if(maxd[y] - (1<<j) < maxd[x]) continue;
            ans += (dis[y] - dis[dp[y][j]]);
            y = dp[y][j];
        }
        if(x == y) return ans;
        for(int j = 20; j >= 0; j--)
        {
            if(dp[x][0] == dp[y][0] )break;
            if(maxd[y] - (1 << j) < 0 || dp[x][j] == dp[y][j]) continue;
            ans += (dis[x]-dis[dp[x][j]] + dis[y] - dis[dp[y][j]]);
            x = dp[x][j], y = dp[y][j];
        }
        ans += (dis[x] - dis[dp[x][0]] + dis[y] - dis[dp[y][0]]);
        return ans;
    }

tarjan
(1).求有向图强连通分量

int tarjan(int id)
{
    vis[id] = 1;
    dfn[id] = low[id] = ++tot;
    sta[index++] = id;
    for(int i = head[id]; ~i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[id] = min(low[id],low[v]);
        }
        else if(vis[v])
            low[id] = min(low[id],dfn[v]);
    }

    if(low[id] == dfn[id])
    {
        int num = 0;
        do
        {
            vis[sta[index--] ] = 0;
            num++;
        }while(sta[index] != id);
        ans[anum ++] = num;
    }
    return 0;
}

(2).求无向图割点

void tarjan(int u,int father)
    {
        dfn[u] = low[u] = ++tot;
        int child = 0;
        for(int i = h[u]; ~i ; i = edge[i].next)
        {
            int v = edge[i].to;
            if(!dfn[v])
            {
                child++;
                tarjan(v,u);
                low[u] = min(low[u],low[v]);
                if(low[v] >= dfn[u]) isCut[u] = 1;
            }
            else if(dfn[v] < dfn[u] && father != v)
                low[u] = min(low[u],dfn[v]);
        }
        if(father == -1 && child == 1) isCut[u] = 0;
    }

(3).求无向图割边(注意割边需要去重,也就是有重边的都不是割边)

int tarjan(int u,int fa)
{
    dfn[u] = low[u] = ++tot;
    for(int i = h[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(dfn[u] < low[v])
            {
                int a = u, b = v;
                if(u > v) swap(a,b);
                edge[i].isb = 1;
            }
        }
        else if(dfn[v] < dfn[u] && v != fa)
            low[u] = min(low[u],dfn[v]);
    }
    return 0;
}

匈牙利算法:

    bool Find(int u)
    {
        for(int i = 1; i < rnum; i++)
            if(g[u][i] && !used[i])
        {
            used[i] = 1;
            if(belong[i] == -1 || Find(belong[i]))
            {
                belong[i] = u;
                return true;
            }
        }
        return false;
    }

2-sat问题
缩点 + 拓扑序

void tarjan(int u)  
{  
    low[u] = dfn[u] = ++tot;  
    S[++snum] = u; inS[u] = 1;  
    for(int i = h[u]; ~i; i = edge[i].next)  
    {  
        int v = edge[i].to;  
        if(!dfn[v])  
        {  
            tarjan(v);  
            low[u] = min(low[u],low[v]);  
        }  
        else if(inS[v])  
            low[u] = min(low[u],dfn[v]);  
    }  
    if(low[u] == dfn[u])  
    {  
        int v = -1;
        snum++;  
        while(v != u)  
        {  
            v = S[snum--];  
            scc[v] = snum; inS[v] = 0;  
        }  
    }  
}  
void solve()  
{  
    for(int i = 0; i < 2*n; i++)  
        if(!dfn[i]) tarjan(i);  
    int flag = 0;  
    for(int i = 0; i < 2*n; i += 2)  
        if(scc[i] == scc[i+1]) {flag = 1; break;}  
    flag == 0 ? printf("YES\n") : printf("NO\n");  
}  

Dinic求最大流 前向弧优化+ 单路增广(因为多路我很迷茫)
bfs求层次图

int bfs()
{
    for(int i = s; i <= t; i++)
        deg[i] = -1;
    queue<int> q;
    q.push(s);  deg[s] = 0;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = h[u]; ~i ; i = edge[i].next)
        {
            int v = edge[i].to,cap = edge[i].cap;
            if(cap && deg[v] == -1)
            {
                deg[v] = deg[u] + 1;
                q.push(v);
            }
        }
    }
    return deg[t] != -1;
}

dfs找增广路

int dfs(int u,int f)
{
    if(u == t) return f;
    for(int i = cur[u]; ~i; i = edge[i].next)
    {
        cur[u] = i;
        int v = edge[i].to, cap = edge[i].cap, rev = edge[i].rev;
        if(cap && deg[v] == deg[u] + 1)
        {
            int k = dfs(v,min(f,cap));
            if(!k)continue;
            edge[i].cap -= k;
            edge[rev].cap += k;
            return k;
        }
    }
    return 0;
}
void solve()
{
    int flow = 0;
    while(bfs())
    {
        for(int i = s; i <= t; i++) cur[i] = h[i];
        while(int k = dfs(s,inf)) flow += k;
    }
   cout << m-flow << endl;
}

E-K + bellman
E-k算法其实就是找增广路的bfs实现,来达到每次都找的是最短增广路的目的。
对于最小费用最大流其实就是每次找费用最少且路径最短的增广路。

int bfs()
{
    for(int i = 0; i < maxn; i++)
        d[i] = inf,a[i] = 0,inq[i] = 0;
    queue<int> q;
    q.push(0);
    d[0] = 0;a[0] = inf;
    inq[0] = 1;
    while(!q.empty())       //找最短且费用最少的增广路
    {
        int u = q.front(); q.pop();
        inq[u] = 0;
        for(int i = h[u]; ~i; i = edge[i].next)
        {
            int v = edge[i].to,cap = edge[i].cap, w = edge[i].w;
            if(cap && d[v] > d[u] + w)
            {
                a[v] = min(a[u],cap);   d[v] = d[u] + w;
                pre[v] = i;
                if(!inq[v]) {q.push(v); inq[v] = 1;}
            }
        }
    }
    if(d[t] == inf ) return 0;
    for(int u = t; u != st; u = edge[pre[u]].from)
    {
        int rev = edge[pre[u]].rev;
        edge[pre[u]].cap -= a[t];
        edge[rev].cap += a[t];
    }
    return d[t];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值