【洛谷】P3544 [POI2012]BEZ-Minimalist Security 的题解

【洛谷】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 0zjpj,所以把所有 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值