那么来一波模板吧=。=

来源:互联网 发布:充值系统源码 编辑:程序博客网 时间:2024/05/16 09:53

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