【洛谷】P3544 [POI2012]BEZ-Minimalist Security 的题解
题目传送门
思路
化下题面给的式子: z ( u ) + z ( v ) = p ( u ) + p ( v ) − b ( u , v ) z(u)+z(v)=p(u)+p(v)-b(u,v) z(u)+z(v)=p(u)+p(v)−b(u,v)
发现 p ( u ) + p ( v ) − b ( u , v ) p(u)+p(v)-b(u,v) p(u)+p(v)−b(u,v) 是确定的,所以只要确定了一个点 i i i 的权值 x ( i ) x(i) x(i),和它在同一个联通块的所有点 j j j 的权值 x ( j ) x(j) x(j) 都确定下来了,并且那些点的权值都可以用 k j z i + b j ( k j ∈ { − 1 , 1 } ) k_jz_i+b_j(k_j\in \{-1,1\}) kjzi+bj(kj∈{−1,1}) 来表示。因此一个联通块的答案 a n s ans ans 为: z i Σ k j + ∑ b j z_i\Sigma {k_j}+\sum{b_j} ziΣkj+∑bj
然后因为限制了 0 ≤ z j ≤ p j 0\le z_j \le p_j 0≤zj≤pj,所以把所有 x ( j ) x(j) x(j) 用 x ( i ) x(i) x(i) 表示出来可以得到一个不等式组。解出来 z ( i ) z(i) z(i) 的极值可以对应到 a n s ans ans 的极值了。
代码
#include<bits/stdc++.h>
#define endl "\n"
#define mem(vis, num) memset(vis, num, sizeof(vis));
#define map mapp
using namespace std;
typedef long long ll;
int p[500005], b[500005], k[500005], cnt = 0, head[500005], mn, mx;
bool vis[500005];
ll ans1 = 0, ans2 = 0, K, B;
struct ed {
int v, w, nxt;
}e[1000005];
void add(int u, int v, int w) {
e[++ cnt] = (ed){v, w, head[u]}, head[u] = cnt;
e[++ cnt] = (ed){u, w, head[v]}, head[v] = cnt;
}
void dfs(int u, int fa) {
if(k[u] < 0) {
mn = max(mn, b[u] - p[u]);
mx = min(mx, b[u]);
}
else {
mn = max(-b[u], mn);
mx = min(p[u] - b[u], mx);
}
K += 1ll * k[u];
B += 1ll * b[u];
if(mn > mx) {
cout << "NIE" << endl;
exit(0);
}
for(int i = head[u]; i; i = e[i].nxt) {
int to = e[i].v, wi = e[i].w;
if(to != fa) {
int tmp = wi - b[u];
if(vis[to]) {
if(k[to] != k[u] && tmp != b[to]) {
cout << "NIE" << endl;
exit(0);
}
else {
if(k[to] == k[u]) {
if((b[to] - tmp) % (-2 * k[u]) != 0) {
cout << "NIE" << endl;
exit(0);
}
mn = max(mn, (b[to] - tmp) / (-2 * k[u]));
mx = min(mx, (b[to] - tmp) / (-2 * k[u]));
if(mn > mx) {
cout << "NIE" << endl;
exit(0);
}
}
}
}
else {
vis[to] = 1;
k[to] = -k[u];
b[to] = tmp;
dfs(to, u);
}
}
}
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m, u, v, w;
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> p[i];
for(int i = 1; i <= m; i ++) {
cin >> u >> v >> w;
add(u, v, p[u] + p[v] - w);
}
for(int i = 1; i <= n; i ++) {
if(!vis[i]) {
vis[i] = 1;
K = B = 0;
k[i] = 1, b[i] = 0;
mx = 100000000, mn = -100000000;
dfs(i, 0);
ans1 += min(1ll * mn * K + B, 1ll * mx * K + B);
ans2 += max(1ll * mn * K + B, 1ll * mx * K + B);
}
}
cout << ans1 << " " << ans2;
return 0;
}