题解:P6755 [BalticOI 2013] Pipes (Day1)
题目等价于:给定一个无向图和所有点的点权,给每条边确定一个边权,使得每个点的点权等于与其相连所有边的边权和除以二。特别地,如果无解或有无数解,只需输出 \(0\) 即可。
共有 \(m\) 个未知数(边权)和 \(n\) 个方程(点权)。由线性代数相关知识可知,若 \(m>n\),则要么方程组无解,要么存在自由未知数,使得方程组有无数解。我们不需要判断到底是无解还是无数解,因此当 \(m>n\) 时直接输出 \(0\) 即可。
因此我们只需考虑 \(m=n-1\) 和 \(m=n\) 的情况。
假设存在一个度数为 \(1\) 的点 \(u\),则与它相连的边的边权可以唯一确定。我们使用拓扑排序不断地剥叶子,并同时确定相关边的边权。
若 \(m=n-1\),则拓扑排序后一定把这棵树剥得只剩一个节点,此时如果这个节点及相关边的权值符合题意,则我们已经构造出了解,否则一定无解。
若 \(m=n\),则这棵基环树被剥得只剩下一个环。
若剩下偶环,则要么方程组无解,要么存在至少一组解(废话)。假设存在一组解,我们对所有边依次编号,将奇数边的边权加一,偶数边的边权减一,则新的边权依然符合题意,故方程组存在无限解。因此,剩下偶环时要么方程组无解,要么方程组有无数解,直接输出 \(0\) 即可。
若剩下奇环,则由线性代数知识可知,这个方程组线性无关,此时必然存在唯一解。使用高斯消元法求解显然不现实。注意到每个方程只有两个未知数,并且形成一个环的形式,我们只需要设出一个未知数 \(x\),递推表示出其他所有未知数,最终进行求解即可。
时间复杂度 \(O(n+m)\)。
//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do {freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);} while(false)
#define endl '\n'
using namespace std;
typedef long long ll;
mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
uniform_int_distribution<int> dist(L, R);
return dist(rnd);
}
template<typename T> void chkmin(T& x, T y) {if(y < x) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
template<int mod>
inline unsigned int down(unsigned int x) {
return x >= mod ? x - mod : x;
}
template<int mod>
struct Modint {
unsigned int x;
Modint() = default;
Modint(unsigned int x) : x(x) {}
friend istream& operator>>(istream& in, Modint& a) {return in >> a.x;}
friend ostream& operator<<(ostream& out, Modint a) {return out << a.x;}
friend Modint operator+(Modint a, Modint b) {return down<mod>(a.x + b.x);}
friend Modint operator-(Modint a, Modint b) {return down<mod>(a.x - b.x + mod);}
friend Modint operator*(Modint a, Modint b) {return 1ULL * a.x * b.x % mod;}
friend Modint operator/(Modint a, Modint b) {return a * ~b;}
friend Modint operator^(Modint a, int b) {Modint ans = 1; for(; b; b >>= 1, a *= a) if(b & 1) ans *= a; return ans;}
friend Modint operator~(Modint a) {return a ^ (mod - 2);}
friend Modint operator-(Modint a) {return down<mod>(mod - a.x);}
friend Modint& operator+=(Modint& a, Modint b) {return a = a + b;}
friend Modint& operator-=(Modint& a, Modint b) {return a = a - b;}
friend Modint& operator*=(Modint& a, Modint b) {return a = a * b;}
friend Modint& operator/=(Modint& a, Modint b) {return a = a / b;}
friend Modint& operator^=(Modint& a, int b) {return a = a ^ b;}
friend Modint& operator++(Modint& a) {return a += 1;}
friend Modint operator++(Modint& a, int) {Modint x = a; a += 1; return x;}
friend Modint& operator--(Modint& a) {return a -= 1;}
friend Modint operator--(Modint& a, int) {Modint x = a; a -= 1; return x;}
friend bool operator==(Modint a, Modint b) {return a.x == b.x;}
friend bool operator!=(Modint a, Modint b) {return !(a == b);}
};
const int N = 1e5 + 5;
int n, m, a[N], deg[N], vis[N], ans[N], k[N], b[N];
vector<tuple<int, int>> e[N];
void toposort() {
queue<int> q;
rep(u, 1, n) if(deg[u] == 1) q.push(u);
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto [v, i]: e[u]) {
if(!vis[i]) {
vis[i] = 1;
ans[i] = a[u] * 2;
a[u] -= ans[i] / 2;
a[v] -= ans[i] / 2;
if(--deg[v] == 1) q.push(v);
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
rep(i, 1, n) cin >> a[i];
rep(i, 1, m) {
int u, v;
cin >> u >> v;
e[u].emplace_back(v, i);
e[v].emplace_back(u, i);
++deg[u]; ++deg[v];
}
if(m > n) {
cout << 0 << endl;
return 0;
}
toposort();
int cnt = 0;
rep(u, 1, n) if(deg[u] == 2) ++cnt;
if(cnt == 0) {
bool ok = true;
rep(u, 1, n) ok &= a[u] == 0;
if(ok) rep(i, 1, m) cout << ans[i] << endl;
else cout << 0 << endl;
}
else if(cnt % 2 == 0) cout << 0 << endl;
else {
vector<int> vec;
rep(u, 1, n) {
if(deg[u] == 2) {
vec.push_back(u);
break;
}
}
rep(t, 0, cnt - 2) {
int u = vec[t], w = t == 0 ? 0 : vec[t - 1];
for(auto [v, i]: e[u]) {
if(deg[v] == 2 && v != w) {
vec.push_back(v);
break;
}
}
}
rep(t, 0, cnt - 1) {
int u = vec[t];
if(t == 0) {
k[t] = 1;
b[t] = 0;
}
else {
k[t] = -k[t - 1];
b[t] = a[u] - b[t - 1];
}
}
int K = k[0] + k[cnt - 1], B = b[0] + b[cnt - 1];
int x = (a[vec[0]] - B) / K;
rep(t, 0, cnt - 1) {
int u = vec[t], w = vec[(t + 1) % cnt];
for(auto [v, i]: e[u]) {
if(v == w) {
ans[i] = (k[t] * x + b[t]) * 2;
break;
}
}
}
rep(i, 1, m) cout << ans[i] << endl;
}
return 0;
}

浙公网安备 33010602011771号