@Dmaxiya
2025-01-26T10:34:41.000000Z
字数 9278
阅读 1523
板子
const int maxn = 5000 + 100;// 欧拉路径输出从cnt – 1 到0输出u点下标,最后输出v点下标struct Node {int to;int Index;Node() {}Node(int t, int i) {to = t;Index = i;}};vector<Node> G[maxn];int deg[maxn];bool visit[maxn];int n, m, v, u;struct Edge {int u, v;Edge() {}Edge(int uu, int vv) {u = uu;v = vv;}};Edge e[maxn];int cnt;void dfs(int x) {int len = G[x].size();for(int i = 0; i < len; ++i) {int Index = G[x][i].Index;int pos = G[x][i].to;if(!visit[Index]) {visit[Index] = true;dfs(pos);e[cnt++] = Edge(x, pos);}}}for(int i = 0; i <= n; ++i) {if(deg[i] % 2 == 1) {u = i;break;}}dfs(u);for(int i = cnt - 1; i >= 0; --i) {printf("%d ", e[i].u);}printf("%d\n", e[0].v);
const int maxn = 1000 + 100;int top, bcnt, dcnt, n;int sta[maxn], dfn[maxn], low[maxn], belong[maxn];bool ins[maxn];vector<int> G[maxn];vector<int> GG[maxn];// G 为原图,GG 为缩点后的图// 缩点后的图总共有 bcnt 个点,下标范围为 [1, bcnt]// 若为无向图,dfs 时只需要多记录一个父节点// 使用时构好图到 G 中,直接调用 Tarjan 函数// belong[a] = b 表示原图上的节点 a 被缩至新图上的节点 bvoid dfs(int x) {dfn[x] = low[x] = ++dcnt;ins[x] = true;sta[top++] = x;int len = G[x].size();for(int i = 0; i < len; ++i) {int pos = G[x][i];if(dfn[pos] == 0) {dfs(pos);low[x] = min(low[x], low[pos]);} else if(ins[pos]) {low[x] = min(low[x], dfn[pos]);}}if(dfn[x] == low[x]) {++bcnt;int pos;do {pos = sta[--top];ins[pos] = false;belong[pos] = bcnt;} while(pos != x);}}void Tarjan() {bcnt = top = dcnt = 0;memset(dfn + 1, 0, sizeof(int) * n);memset(ins + 1, 0, sizeof(bool) * n);for(int i = 1; i <= n; ++i) {if(dfn[i] == 0) {dfs(i);}}for(int i = 1; i <= bcnt; ++i) {GG[i].clear();}for(int i = 1; i <= n; ++i) {int len = G[i].size();for(int j = 0; j < len; ++j) {int pos = G[i][j];int u = belong[i];int v = belong[pos];if(u != v) {GG[u].push_back(v);}}}}
const int Log = 20;const int maxn = 100000 + 100;int idCnt;int st[maxn][Log];vector<int> G[maxn];int id[maxn];// Log 等于树的层数取 log 的值,节点下标从 1 开始void dfs(int root, int fa) {id[root] = ++idCnt;st[root][0] = fa;for(int j = 1; j < Log; ++j) {st[root][j] = st[st[root][j - 1]][j - 1];}for (int pos : G[root]) {if (pos != fa) {dfs(pos, root);}}}int lca(int x, int y) {if(x == y) {return x;}if(id[x] > id[y]) {swap(x, y);}for(int i = Log - 1; i >= 0; --i) {if(id[st[y][i]] > id[x]) {y = st[y][i];}}return st[y][0];}
const int maxn = 100 + 100;int dis[maxn];vector<Node> G[maxn];priority_queue<Node> que;// 优先队列为小顶堆,排序关键字为Node.dis,形参s 为起点下标void dij(int s) {memset(dis, 0x3f, sizeof(dis));dis[s] = 0;que.push(Node(s, 0));while(!que.empty()) {Node tmp = que.top();que.pop();int len = G[tmp.pos].size();for(int i = 0; i < len; ++i) {int pos = G[tmp.pos][i].pos;int d = G[tmp.pos][i].dis;if(dis[pos] > tmp.dis + d) {dis[pos] = tmp.dis + d;que.push(Node(pos, dis[pos]));}}}}
const int maxn = 100000 + 100;vector<Node> G[maxn];priority_queue<Node> que;int dis1[maxn], dis2[maxn];// 优先队列为小顶堆,排序关键字为Node.dis,形参s 为起点下标// dis1 为最短路,dis2 为次短路void dij(int s) {memset(dis1, 0x3f, sizeof(dis1));memset(dis2, 0x3f, sizeof(dis2));dis1[s] = 0;que.push(Node(s, 0));while(!que.empty()) {Node tmp = que.top();que.pop();int pos = tmp.pos;int dis = tmp.dis;if(dis2[pos] < dis) {continue;}int len = G[pos].size();for(int i = 0; i < len; ++i) {tmp = G[pos][i];int to = tmp.pos;int d2 = dis + tmp.dis;if(dis1[to] > d2) {swap(d2, dis1[to]);que.push(Node(to, dis1[to]));}if(dis2[to] > d2 && dis1[to] < d2) {dis2[to] = d2;que.push(Node(to, dis2[to]));}}}}
const int maxn = 1000 + 100;const int INF = 0x3f3f3f3f;struct Node {int pos, dis;Node() {}Node(int p, int d) {pos = p;dis = d;}};int incnt[maxn], dis[maxn];bool inque[maxn];vector<Node> G[maxn];// maxn 为节点个数,下标从 1 开始// incnt 表示第 i 个节点入队的次数// dis 表示以 s 为起点的最短路// spfa 返回 false 表示有负环bool spfa(int s, int n) {memset(inque + 1, 0, sizeof(bool) * n);memset(dis + 1, 0x3f, sizeof(int) * n);memset(incnt + 1, 0, sizeof(int) * n);dis[s] = 0;inque[s] = true;incnt[s] = 1;queue<int> que;que.push(s);while(!que.empty()) {int tmp = que.front();que.pop();inque[tmp] = false;int len = G[tmp].size();for(int i = 0; i < len; ++i) {int pos = G[tmp][i].pos;int d = G[tmp][i].dis;if(dis[pos] > dis[tmp] + d) {dis[pos] = dis[tmp] + d;if(!inque[pos]) {inque[pos] = true;que.push(pos);if(++incnt[pos] > n) {return false;}}}}}return true;}
const int maxn = 1000 + 100;int n;int pre[maxn];int ddis[maxn];int dis[maxn][maxn];bool visit[maxn];queue<int> que;vector<int> G[maxn];// n 为图上节点数量,pre表示节点i与生成树距离最短连边的节点// ddis表示节点i到最小生成树的距离,dis为完全图上任意两点间距离// visit表示是否在最小生成树上,G为最小生成树void Prim() {memset(visit, 0, sizeof(visit));memset(ddis, 0x3f, sizeof(ddis));for(int i = 1; i <= n; ++i) {G[i].clear();}que.push(1);while(!que.empty()) {int tmp = que.front();que.pop();ddis[tmp] = 0;visit[tmp] = true;int Min = INT_MAX;int pos = -1;for(int i = 1; i <= n; ++i) {if(!visit[i]) {if(ddis[i] > dis[tmp][i]) {ddis[i] = dis[tmp][i];pre[i] = tmp;}}}for(int i = 1; i <= n; ++i) {if(!visit[i] && Min > ddis[i]) {Min = ddis[i];pos = i;}}if(pos != -1) {tmp = pre[pos];que.push(pos);G[tmp].push_back(pos);G[pos].push_back(tmp);}}}
const int maxn = 1000 + 100;int fa[maxn];// 节点下标范围为[from, to]inline void init(int from, int to) {For(i, from, to) fa[i] = i;}int Find(int x) {return ((x == fa[x])? x: (fa[x] = Find(fa[x])));}void unit(int x, int y) {int xx = Find(x);int yy = Find(y);fa[xx] = yy;}
const int maxn = 3001;int Nx, Ny;int dx[maxn], dy[maxn];int Mx[maxn], My[maxn];vector<int> G[maxn];bool vis[maxn];// 使用时需设好 Nx Ny 和 G,G 中只需要存下从 Nx 到 Ny 所有节点的边,不需要从 Ny 到 Nx 的边// 时间复杂度 O(sqrt(n)*m),n 为节点数,m为边数// Nx, Ny 分别表示左右两边节点数量,编号从 1 开始// 最终匹配结果存在 Mx 与 My 中// Mx[a] = b 表示左边的 a 与右边的 b 匹配,同时 My[b] = a// 直接调用 hopcroft_karp 函数返回最大匹配数量bool Find(int x) {int len = G[x].size();for(int i = 0; i < len; ++i) {int pos = G[x][i];if(!vis[pos] && dy[pos] == dx[x] + 1) {vis[pos] = true;if(My[pos] == 0 || Find(My[pos])) {My[pos] = x;Mx[x] = pos;return true;}}}return false;}int hopcroft_karp() {int ret = 0;memset(Mx + 1, 0, sizeof(int) * Nx);memset(My + 1, 0, sizeof(int) * Ny);bool flag = true;while(flag) {flag = false;queue<int> que;for(int i = 1; i <= Nx; ++i) {if(Mx[i] == 0) {que.push(i);}}memset(dx + 1, 0, sizeof(int) * Nx);memset(dy + 1, 0, sizeof(int) * Ny);memset(vis + 1, 0, sizeof(bool) * Ny);while(!que.empty()) {int x = que.front();que.pop();int len = G[x].size();for(int i = 0; i < len; ++i) {int pos = G[x][i];if(dy[pos] == 0) {dy[pos] = dx[x] + 1;if(My[pos] != 0) {dx[My[pos]] = dy[pos] + 1;que.push(My[pos]);} else {flag = true;}}}}if(!flag) {break;}for(int i = 1; i <= Nx; ++i) {if(!Mx[i] && Find(i)) {++ret;}}}return ret;}
const int maxn = 301;const LL INF = 1e18;int n;LL G[maxn][maxn];LL lx[maxn], ly[maxn], slack[maxn];int My[maxn], Mx[maxn];int pre[maxn];bool visy[maxn];// 使用时需设好 n 和 G,下标从 1 开始// 时间复杂度 O(n^3),n 为节点数// 最终匹配结果存在 Mx 与 My 中// Mx[a] = b 表示左边的 a 与右边的 b 匹配,同时 My[b] = a// 直接调用 KM 函数返回最大匹配权值// 求最小权匹配可将权值取相反数void augment(int root) {fill(visy + 1, visy + n + 1, false);fill(slack + 1, slack + n + 1, INF);int py;My[py = 0] = root;do {visy[py] = true;int x = My[py], yy;LL delta = INF;for(int y = 1; y <= n; y++) {if(!visy[y]) {if(lx[x] + ly[y] - G[x][y] < slack[y]) {slack[y] = lx[x] + ly[y] - G[x][y];pre[y] = py;}if(slack[y] < delta) {delta = slack[y];yy = y;}}}for(int y = 0; y <= n; y++) {if(visy[y]) {lx[My[y]] -= delta;ly[y] += delta;} else {slack[y] -= delta;}}py = yy;} while(My[py] != -1);do {int Pre = pre[py];My[py] = My[Pre];py = Pre;} while(py != 0);}LL KM() {for(int i = 1; i <= n; i++) {lx[i] = ly[i] = 0;My[i] = -1;for(int j = 1; j <= n; j++) {lx[i] = max(lx[i], G[i][j]);}}LL answer = 0;for(int root = 1; root <= n; root++) {augment(root);}for(int i = 1; i <= n; ++i) {Mx[My[i]] = i;}for(int i = 1; i <= n; i++) {answer += lx[i];answer += ly[i];}return answer;}
const int maxn = 200 + 100;const int maxm = 200 + 100;const int INF = 0x3f3f3f3f;// 时间复杂度为 O(n^2 * m),n 为节点数量,m 为边数// maxm 为需要加边的数量,即调用 addEdge 的总次数// 使用前需调用 Init 初始化struct Edge {int to, Next, flow, cap;Edge() {}Edge(int t, int n, int f, int c) {to = t;Next = n;flow = f;cap = c;}};int N, S, T, ecnt;int head[maxn], cur[maxn], d[maxn];Edge edge[maxm << 1];// 节点总个数,节点编号从 0 ~ N - 1void Init(int n) {N = n;ecnt = 0;memset(head, -1, sizeof(int) * N);}void addEdge(int u, int v, int c) {edge[ecnt] = Edge(v, head[u], 0, c);head[u] = ecnt++;edge[ecnt] = Edge(u, head[v], 0, 0);head[v] = ecnt++;}void add_s_t() {// 将源点和汇点连入图中}bool bfs() {queue<int> que;for(int i = 0; i < N; ++i) {d[i] = 0;}que.push(S);d[S] = 1;while(!que.empty()) {int tmp = que.front();que.pop();for(int id = head[tmp]; id != -1; id = edge[id].Next) {if(d[edge[id].to] == 0 && edge[id].cap > edge[id].flow) {d[edge[id].to] = d[tmp] + 1;que.push(edge[id].to);}}}return d[T] != 0;}int dfs(int x, int res) {if(x == T || res == 0) {return res;}int ret = 0, tmp;for(int &id = cur[x]; id != -1; id = edge[id].Next) {int pos = edge[id].to;if(d[pos] == d[x] + 1 && edge[id].cap > edge[id].flow) {tmp = dfs(pos, min(res, edge[id].cap - edge[id].flow));if(tmp > 0) {ret += tmp;res -= tmp;edge[id].flow += tmp;edge[id ^ 1].flow -= tmp;if(res == 0) {break;}}}}return ret;}// 调用 Dinic 前需构好图// 直接调用函数返回 maxflowint Dinic(int s, int t) {int flow = 0;S = s;T = t;add_s_t();while(bfs()) {for(int i = 0; i < N; ++i) {cur[i] = head[i];}flow += dfs(S, INF);}return flow;}
const int maxn = 1000 + 100;const int maxm = 20000 + 100;const int INF = 0x3f3f3f3f;// 时间复杂度为流量 * 边数 * 常数(2)// 求最大费用只需要将费用取相反数// maxm 为需要加边的数量,即调用 addEdge 的总次数// 使用前需调用 Init 初始化struct Edge {int to, Next, cap, flow, cost;Edge() {}Edge(int t, int n, int ca, int f, int co) {to = t;Next = n;cap = ca;flow = f;cost = co;}};int N;int head[maxn], ecnt;int pre[maxn], dis[maxn];bool inque[maxn];Edge edge[maxm << 1];// 节点总个数,节点编号从 0 ~ N - 1void Init(int n) {N = n;ecnt = 0;memset(head, -1, sizeof(int) * N);}void addEdge(int u, int v, int cap, int cost) {edge[ecnt] = Edge(v, head[u], cap, 0, cost);head[u] = ecnt++;edge[ecnt] = Edge(u, head[v], 0, 0, -cost);head[v] = ecnt++;}void add_s_t() {// 将源点和汇点连入图中}bool spfa(int s, int t) {queue<int> que;for(int i = 0; i < N; i++) {dis[i] = INF;inque[i] = false;pre[i] = -1;}dis[s] = 0;inque[s] = true;que.push(s);while(!que.empty()) {int u = que.front();que.pop();inque[u] = false;for(int i = head[u]; i != -1; i = edge[i].Next) {int v = edge[i].to;if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) {dis[v] = dis[u] + edge[i].cost;pre[v] = i;if(!inque[v]) {inque[v] = true;que.push(v);}}}}return pre[t] != -1;}// 调用 minCostMaxflow 前需构好图// 返回的是 maxflow,cost存的是最小费用int minCostMaxflow(int s, int t, int &cost) {int flow = 0;cost = 0;add_s_t();while(spfa(s,t)) {int Min = INF;for(int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) {if(Min > edge[i].cap - edge[i].flow) {Min = edge[i].cap - edge[i].flow;}}for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {edge[i].flow += Min;edge[i ^ 1].flow -= Min;cost += edge[i].cost * Min;}flow += Min;}return flow;}