1 条题解
-
0
题目大意
给定 个城市和 条道路,第 条道路连接 和 ,建造成本为 。每个城市有奇偶性要求 ( 表示要求度数为偶数, 表示要求度数为奇数)。需要支持:
- 输出初始时第 便宜的满足条件的道路集合
- 修改城市的奇偶性要求
- 修改 值
- 查询当前方案是否包含某条道路
问题分析
度数约束与线性代数
这是一个典型的度数约束子图选择问题。对于无向图 ,每个顶点 有度数奇偶性要求 ,我们需要选择边集 使得对于每个顶点 ,。
在模 的线性代数框架下,这个问题可以表述为:
设 是图的关联矩阵(,在 上), 是需求向量,我们需要解方程:
其中 表示每条边是否被选择。
解空间结构
根据线性代数理论:
- 如果方程有解,解空间的维数为
- 解的数量为 (如果存在)
对于连通图,关联矩阵的秩为 (在 上),因此解空间维数为 。
成本优化与第 小解
由于成本是 且严格递增,这实际上构成了一个二进制表示。第 条边是否选择对应二进制第 位。
寻找第 便宜的解等价于在解空间中按二进制表示(从低位到高位)寻找第 小的向量。
算法思路
基础解法
- 构建线性基:在 上求解 ,找到一组基础解
- 解空间表示:任何解可以表示为特解 + 齐次解空间的线性组合
- 第 小解:将自由变量按成本升序排列, 的二进制表示直接决定哪些自由变量被选择
高效实现
由于 ,需要高效算法:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 500005; // 并查集维护连通性 struct DSU { vector<int> parent, rank; DSU(int n) : parent(n), rank(n, 0) { iota(parent.begin(), parent.end(), 0); } int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); } bool unite(int x, int y) { x = find(x), y = find(y); if (x == y) return false; if (rank[x] < rank[y]) swap(x, y); parent[y] = x; if (rank[x] == rank[y]) rank[x]++; return true; } }; // 线性基模2 struct LinearBasis { vector<bitset<MAXN>> basis; vector<int> pivot; int rank; LinearBasis(int n) : basis(n), pivot(n, -1), rank(0) {} bool insert(bitset<MAXN> vec, int idx) { for (int i = 0; i < basis.size(); i++) { if (vec[i]) { if (pivot[i] == -1) { basis[i] = vec; pivot[i] = idx; rank++; return true; } vec ^= basis[i]; } } return false; } bitset<MAXN> solve(bitset<MAXN> target) { bitset<MAXN> result; for (int i = 0; i < basis.size(); i++) { if (target[i]) { if (pivot[i] == -1) return bitset<MAXN>(); // 无解 target ^= basis[i]; result.set(pivot[i]); } } return result; } }; class ParityRoads { private: int n, m; vector<pair<int, int>> edges; vector<int> parity; ll k; vector<int> current_solution; public: void init(int n, int m, vector<pair<int, int>> edges, vector<int> parity, ll k) { this->n = n; this->m = m; this->edges = edges; this->parity = parity; this->k = k; compute_solution(); } void change_parity(int city) { parity[city] ^= 1; compute_solution(); } void change_k(ll new_k) { k = new_k; compute_solution(); } int query_edge(int edge_id) { if (current_solution.empty()) return -1; return current_solution[edge_id - 1]; } private: void compute_solution() { // 构建关联矩阵 vector<bitset<MAXN>> equations(n); for (int i = 0; i < m; i++) { int u = edges[i].first - 1, v = edges[i].second - 1; equations[u].set(i); equations[v].set(i); } // 构建需求向量 bitset<MAXN> target; for (int i = 0; i < n; i++) { if (parity[i]) target.set(i); } // 高斯消元求解 LinearBasis basis(n); vector<int> free_vars; for (int i = 0; i < m; i++) { bitset<MAXN> eq; for (int j = 0; j < n; j++) { if (equations[j][i]) eq.set(j); } if (!basis.insert(eq, i)) { free_vars.push_back(i); } } // 检查解是否存在 bitset<MAXN> particular = basis.solve(target); if (particular.none() && target.any()) { current_solution.clear(); return; } // 构建第k小解 current_solution.assign(m, 0); // 设置特解部分 for (int i = 0; i < m; i++) { if (particular[i]) { current_solution[i] = 1; } } // 自由变量按k的二进制位设置 sort(free_vars.begin(), free_vars.end()); ll temp_k = k - 1; // k=1对应所有自由变量为0 for (int i = 0; i < free_vars.size(); i++) { if (temp_k & (1LL << i)) { current_solution[free_vars[i]] ^= 1; } } } };关键优化
- 稀疏矩阵处理:使用
bitset高效处理稀疏的关联矩阵 - 动态维护:当奇偶性要求改变时,只需重新计算特解,自由变量基不变
- 第 小计算:自由变量按边编号排序, 的二进制位直接映射
复杂度分析
- 预处理:,其中 是字长(约64)
- 每次修改: 重新计算特解
- 查询:
对于 ,使用
bitset优化后实际可运行。总结
本题的核心是将度数约束问题转化为 上的线性方程组求解,利用线性基技术找到解空间,再根据成本的二进制特性高效找到第 小解。
算法标签:图论、线性代数、高斯消元、bitset优化、解空间枚举
- 1
信息
- ID
- 4573
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者