图结构模板

#include<bits/stdc++.h>
#define MAXN 100000
#define D 10
#define MAXM 10000010
using std::cin;
using std::cout;
using std::endl;
int m, n;//m为边数,n为点数
//图的存储

//邻接矩阵
int a[5010][5010];
void init() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        a[x][y] = 1;
    }
}

//边表
struct node {
    int x, y;
} edge[MAXM + D];

void init() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i)
        cin >> edge[i].x >> edge[i].y;
}

//前向星
struct node {
    int x, y;
} edge[500010];

int st[MAXN + D], en[MAXN + D];

inline bool cmp(node x, node y) {
    return x.x < y.y;
}

void init() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) cin >> edge[i].x >> edge[i].y;
    std::sort(edge + 1, edge + 1 + m, cmp);
    st[edge[1].x] = 1;
    for (int i = 2; i <= m; ++i) {
        if (edge[i].x != edge[i - 1].x) en[edge[i - 1].x] = i - 1;
        st[edge[i].x] = i;
    }
    en[edge[m].x] = m;
}

//链表/链式前向星
int lin[MAXN + D], len = 0;
struct node {
    int y, ne;
} edge[MAXM + D];

inline void addedge(int x, int y) {
    edge[++len].y = y;
    edge[len].ne = lin[x];
    lin[x] = len;
}

void init() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        addedge(x, y);
    }
}

//图的遍历
//DFS
void dfs(int x) {
    vis[x] = true;
    for (int i = lin[x], y; i; i = edge[i].ne)
     if (!vis[y = edge[i].y]) dfs(y);
}

//DFS(邻接矩阵)
void dfs(int x) {
    vis[x] = true;
    for (int i = 1; i <= n; ++i) if (a[x][i] && !vis[i]) dfs(i);
}

//BFS
int head, tail, queue[MAXN + D];
void bfs(int s) {
    vis[s] = true;
    head = 0, tail = 1;
    queue[1] = s;
    while (head++ < tail) {
        int x = queue[head];
        for (int i = lin[x], y; i; i = edge[i].ne)
         if (!vis[y = edge[i].y])
              {
                queue[++tail] = y;
                vis[y] = true;
            }
    }
}

//BFS(邻接矩阵)
int head, tail, queue[MAXN + D];
void bfs(int s) {
    vis[s] = true;
    head = 0, tail = 1;
    queue[1] = s;
    while (head++ < tail) {
        int x = queue[head];
        for (int i = 1; i <= n; ++i) if (a[x][i] && !vis[i]) {
                queue[++tail] = i;
                vis[i] = true;
            }
    }
}

//最短路
//Floyd
void Floyd() {
    for (int k = 1; k <= n; ++k) for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) a[i][j] = std::min(a[i][j], a[i][k] + a[k][j]);
}

//Dijkstra
#define INF 0x3f3f3f3f
int dis[10010];
int vis[10010];
void Dijkstra(int s) {
    memset(vis, false, sizeof(vis));
    for (int i = 1; i <= n; i++) dis[i] = a[s][i];
    vis[s] = true;
    for (int i = 1; i < n; ++i) {
        int min = INF, x = 0;
        for (int i = 1; i <= n; ++i)
            if (!vis[i] && dis[i] < min) {
                min = dis[i];
                x = i;
            }
        if (!x) return;
        vis[x] = true;
        for (int i = 1; i <= n; ++i) dis[i] = std::min(dis[i], dis[x] + a[x][i]);
    }
}

//Dijkstra_with_priority_queue
using std::pair;
using std::priority_queue;
using std::vector;
using std::greater;
using std::make_pair;
#define INF 0x3f3f3f3f
typedef pair<int, int> pii;
pirority_queue<pii, vector<pii>, greater<pii> > queue;
void Dijkstra(int s) {
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[s] = 0;
    queue.push(make_pair(dis[s], 0));
    while (!q.empty()) {
        pii tmp = q.top();
        q.pop();
        int x = tmp.second;
        if (vis[x]) continue;
        vis[x] = true;
        for (int i = lin[x], y; i; i = edge[i].ne) if (dis[y = edge[i].y] > dis[x] + edge[i].v) {
                dis[y] = dis[x] + edge[i].v;
                if (!vis[y]) q.push(make_pair(dis[y], y));
            }
    }
}

//Bellman-Ford
void Bellman_Ford(int s) {
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    bool rel;
    for (int i = 1; i <= n; ++i) {
        rel = false;
        for (int j = 1; j <= len; ++j) if (dis[edge[j].y] > dis[edge[j].x] + edge[j].v)
            }
}

//SPFA
int queue[10000010], head, tail;
void SPFA(int s) {
    head = 0, tail = 1;
    memset(vis, false, sizeof(vis));
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    vis[s] = true;
    queue[1] = s;
    while (head++ < tail) {
        int x = queue[head];
        vis[x] = false;
        for (int i = lin[x], y; i; i = edge[i].ne) if (dis[y = edge[i].y] > dis[x] + edge[i].v) {
                dis[y] = dis[x] + edge[i].v;
                if (!vis[y]) {
                    vis[y] = true;
                    queue[++tail] = y;
                }
            }
    }
}

//最小生成树
//Prim
#define INF 0x3f3f3f3f
int Prim() {
    memset(vis, false, sizeof(vis));
    vis[1] = true;
    int sum = 0;
    for (int i = 1; i <= n; ++i) dis[i] = a[1][i];
    for (int i = 1; i < n; ++i) {
        int min = INF, x = 0;
        for (int j = 1; j <= n; ++j) if (!vis[j] && dis[j] < min) {
                min = dis[j];
                x = j;
            }
        vis[x] = true;
        sum += min;
        for (int j = 1; j <= n; ++j) dis[j] = std::min(dis[j], a[x][j]);
    }
    return sum;
}

//Kruskal
struct node {
    int x, y, v;
} edge[100010];

inline bool cmp(node x, node y) {
    return x.v <y.v;
}

int father[MAXN + D];

int getfather(int x) {
    return (father[x] == x) ? x : (father[x] = getfather(father[x]));
}

int Kruskal() {
    for (int i = 1; i <= n; ++i) father[i] = i;
    int sum = 0, cnt = 0;
    std::sort(edge + 1, edge + 1 + m, cmp);
    for (int i = 1; i <= m && cnt < n - 1; ++i) {
        int x = getfather(edge[i].x), y = getfather(edge[i].y);
        if (x != y) {
            ++cnt;
            sum += edge[i].v;
            father[x] = y;
        }
    }
    return sum;
}

//拓扑排序
int queue[MAXN + D], head, tail, in_degree[MAXN + D], ans[100][MAXN + D], tot = 0;

void init() {
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        addedge(x, y);
        ++in_degree[y];
    }
}

//BFS
void bfs() {
    head = 0, tail = 0;
    for (int i = 1; i <= n; ++i) if (!in_degree[i]) queue[++tail] = y;
    while (head++ < tail) {
        int x = queue[head];
        for (int i = lin[x],y; i; i = edge[i].ne) if (!(--in_degree[y = edge[i].y])) queue[++tail] = y;
    }
}

//DFS
void dfs(int x, int dep) {
    queue[dep] = x;
    vis[x] = true;
    if (dep == n) {
        ++tot;
        for (int i = 1; i <= n; ++i) ans[tot][i] = queue[i];
        vis[x] = false;
    }
    for (int i = lin[x]; i; i = edge[i].ne) --in_degree[edge[i].y];
    for (int i = 1; i <= n; ++i) if (!vis[i] && !in_degree[i]) dfs(i, dep + 1);
    for (int i = lin[x]; i; i = edge[i].ne) ++in_degree[edge[i].y];
    vis[x] = false;
}

//Tarjan
//割点
int dfn[MAXN + D], low[MAXN + D], _clock = 0;
bool iscut[MAXN + D]
void tarjan(int x, int par = 0) {
    int child = 0;
    dfn[x] = low[x] = ++_clock;
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if ((y = edge[i].y) == par) continue;
        if (!dfn[y]) {
            tarjan(y, x);
            if (low[y] < low[x]) low[x] = low[y];
            else if (low[y] >= dfn[x]) ++child;
        } else if (dfn[y] < low[x]) low[x] = dfn[y];
    }
    if (child >= 2 || (child == 1 && par)) iscut[x] = true;
}

int main() {
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//点双连通分量
using std::vector;
vector<int> bcc[MAXN + D];
int size[MAXN + D], dfn[MAXN + D], low[MAXN + D], _clock = 0, bel[MAXN + D], stack[MAXM + D], top = 0;
void tarjan(int x, int par = 0) {
    int child = 0;
    dfn[x] = low[x] = ++_clock;
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if ((y = edge[i].y) == par) continue;
        if (!dfn[y]) {
            stack[++top] = i;
            tarjan(y, x);
            if (low[y] < low[x]) low[x] = low[y];
            else if (low[y] >= dfn[x]) {
                ++child;
                int k;
                ++tot;
                do {
                    k = stack[top--];
                    if (bel[edge[k].x] != tot) {
                        bel[edge[k].x] = tot;
                        bcc[tot].push_back(edge[k].x);
                        ++size[tot];
                    }
                    if (bel[edge[k].y] != tot) {
                        bel[edge[k].y] = tot;
                        bcc[tot].push_back(edge[k].y);
                        ++size[tot];
                    }
                } while (k != i);
            }
        } else if (dfn[y] < low[x]) {
            low[x] = dfn[y];
            stack[++top] = i;
        }
    }
    if (child >= 2 || (par && child)) iscut[x] = true;
}

int main() {
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//割边
int dfn[MAXN + D], low[MAXN + D], _clock = 0, rev[(MAXM << 1) + D];
bool isbridge[(MAXM << 1) + d];
void tarjan(int x, int par = 0) {
    dfn[x] = low[x] = ++_clock;
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if (i == par) continue;
        if (!dfn[y = edge[i].y]) {
            tarjan(y, rev[i]);
            if (low[y] < low[x]) low[x] = low[y];
        } else if (dfn[y] < low[x]) low[x] = dfn[y];
    }
    if (dfn[x] == low[x]) isbridge[par] = isbridge[rev[par]] = true;
}

int main() {
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//求割边后求边双连通分量
int tot = 0, bel[MAXN + D], size[MAXN + D];
void dfs(int i) {
    bel[i] = tot;
    ++size[tot];
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if (isbridge[i] || bel[y = edge[i].y]) continue;
        dfs(y);
    }
}

int main() {
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
    for (int i = 1; i <= n; ++i) if (!bel[i]) {
            ++tot;
            dfs(i);
        }
}

//连通分量
int dfn[MAXN + D], low[MAXN + D], _clock = 0, top = 0, stack[MAXN + D], bel[MAXN + D], size[MAXN + D], tot;
bool vis[MAXN + D];
void tarjan(int x) {
    vis[x] = true;
    stack[++top] = x;
    dfn[x] = low[x] = ++_clock;
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if (!dfn[y = edge[i].y]) {
            tarjan(y);
            if (low[y] < low[x]) low[x] = low[y];
        } else if (vis[y] && dfn[y] < low[x]) low[x] = dfn[y];
    }
    if (dfn[x] == low[x]) {
        int k;
        tot++;
        do {
            k = stack[top--];
            vis[k] = false;
            ++size[tot];
            bel[k] = tot;
        } while (k != x);
    }
}

int main() {
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
}

//DFS序列化
int st[MAXN + D], en[MAXN + D], _clock = 0;
void dfs(int x, int par = 0) {
    st[x] = ++_clock;
    for (int i = lin[x], y; i; i = edge[i].ne) if ((y = edge[i].y) != par) dfs(y, x);
    en[x] = _clock;
}

//轻重链剖分
int st[MAXN + D], en[MAXN + D], _clock = 0, top[MAXN + D], size[MAXN + D], son[MAXN + D], father[MAXN + D], depth[MAXN + D];
void find_heavy_edge(int x, int par = 0) {
    father[x] = par;
    depth[x] = depth[par] + 1;
    size[x] = 1;
    int maxsize = 0;
    son[x] = 0;
    for (int i = lin[x], y; i; i = edge[i].y) {
        if ((y = edge[i].y) == par) continue;
        find_heavy_edge(y, x);
        if (size[y] > maxsize) {
            maxsize = size[y];
            son[x] = y;
        }
        size[x] += size[y];
    }
}

void connect_heavy_edge(int x, int par) {
    st[x] = ++_clock;
    top[x] = par;
    if (son[x]) connect_heavy_edge(son[x], par);
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (y == par || y == son[x]) continue;
        connect_heavy_edge(y, y);
    }
    en[x] = _clock;
}

int main() {
    find_heavy_edge(1);
    connect_heavy_edge(1, 1);
}

//LCA
//树链剖分
int LCA(int u, int v) {
    while (top[u] != top[v]) {
        if (depth[top[u]] < depth[top[v]]) std::swap(u, v);
        u = father[top[u]];
    }
    if (depth[u] > depth[v]) std::swap(u, v);
    return v;
}

//倍增法
int father[MAXN + D][20], depth[MAXN + D], M;
void dfs(int x) {
    for (int i = 1; (1 << i) <= n && father[x][i - 1]; ++i) father[x][i] = father[father[x][i - 1]][i - 1];
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if ((y = edge[i].y) == father[x][0]) continue;
        father[y][0] = x;
        dfs(y);
    }
}

int LCA(int u, int v) {
    if (depth[u] < depth[v]) std::swap(u, v);
    for (int i = 0; depth[u] != depth[v]; ++i) if ((1 << i) & (depth[u] - depth[v])) u = father[u][i];
    if (u == v) return u;
    for (int i = M; i >= 0; --i) if (father[u][i] != father[v][i]) {
            u = father[u][i];
            v = father[v][i];
        }
    return father[u][0];
}

int main() {
    for (M = 0; (1 << M) <= n; ++M);
    --M;
    dfs(1);
}

//tarjan离线法
struct query {
    int y, ne, id;
} query[MAXM + D];

int len_query = 0, lin_query[MAXN + D], father[MAXN + D], ans[MAXM + D];
bool vis[MAXN + D];
inline void addquery(int x, int y, int id) {
    query[++len_query].y = y;
    query[len_query].ne = lin_query[x];
    lin_query[x] = len_query;
    query[len_query].id = id;
}

int getfather(int x) {
    return (father[x] == x) ? x : (father[x] = getfather(father[x]));
}

void tarjan(int x, int par = 0) {
    for (int i = lin[x], y; i; i = edge[i].ne) {
        if ((y = edge[i].y) == par) continue;
        tarjan(y, x);
        father[y] = x;
        vis[y] = true;
    }
    for (int i = lin_query[x], y; i; i = query[i].ne) {
        if (!vis[y = query[i].y]) continue;
        ans[query[i].id] = getfather(y);
    }
}

int main() {
    for (int i = 1; i <= n; ++i) father[i] = i;
    tarjan(1);
}

//点分治
int size[MAXN + D], root, sum = 0, maxsize[MAXN + D];
bool vis[MAXN + D];
void getroot(int x, int par) {
    size[x] = 1;
    maxsize[x] = 0;
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (y == par || vis[y]) continue;
        getroot(y, x);
        maxsize[x] = std::max(maxsize[x], size[y]);
        size[x] += size[y];
    }
    maxsize[x] = std::max(maxsize[x], sum - maxsize[x]);
    if (maxsize[x] < maxsize[root]) root = x;
}

void cal(int x, int par) {
//计算当前点贡献
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (vis[y] || y == par) continue;
        cal(y, x);
    }
}

void add(int x, int par, bool opt) {
    if (opt) {
//将当前点加入到计算的点中
    } else {
//将当前点从已计算的点集删除
    }
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (vis[y] || y == par) continue;
        add(y, x, opt);
    }
}

void solve(int x) {
    getroot(x);
    vis[x] = true;
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (vis[y]) continue;
        cal(y, x);
        add(y, x, true);
    }
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (vis[y]) continue;
        add(y, x, false);
    }
    for (int i = lin[x], y; i; i = edge[i].ne) {
        y = edge[i].y;
        if (vis[y]) continue;
        sum = size[y];
        root = 0;
        getroot(y, x);
        solve(root);
    }
}

大量图结构模板,可能会有帮助...

原文地址:https://www.cnblogs.com/AK-ls/p/10107699.html