【题目描述】
给出一个N个顶点、M条边的无向图,边(u,v)有权值w(u,v),顶点i也有权值p(i),
并且对于每条边(u,v)都满足p(u)+p(v)>=w(u,v)。
现在要将顶点i的权值减去z(i),其中0≤z(i)≤p(i)。
修改后设顶点i的权值p'(i)=p(i)-z(i),对于每条边(u,v)都满足p'(u)+p'(v)=w(u,v)。
求sum{z(i)}的最小值和最大值。
【输入】
第一行两个正整数n,m (n≤500,000, m≤3,000,000)。
第二行n个整数,依次表示p(1),p(2),...,p(n) (0≤p(i)≤10^6)。
下面m行,每行三个整数u,v,w (1≤u,v≤n, 0≤w≤10^6),表示存在一条权值为w的边(u,v)。
【输出】
两个正整数,分别表示sum{z(i)}的最小值和最大值,如果不存在方案就输出NIE。
【输入样例】
For the input data: 3 2 5 10 5 1 2 5 2 3 3 the correct result is: 12 15 whereas for the following input data: 3 3 1 1 1 1 2 1 1 3 1 3 2 1 the correct result is: NIE
【提示】
很简单的一道题,发现一个点的值定了,那么其它点都确定了。
那么我们把一个点设出来,dfs出一棵树,设根为x。
用树上的边推出所有点关于x的一次函数。
一边dfs点值一边更新x的取值范围
最后再用非树边验证是否满足就可以了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define LL long long
using namespace std;
const int maxn = 3e6 + 5;
struct edge {
int v, w, next;
} e[maxn << 1];
int head[maxn], cnt, u, v, w;
void adde(const int &u, const int &v, const int &w) {
e[++cnt] = (edge) {v, w, head[u]};
head[u] = cnt;
}
int op[maxn], n, m;
LL l, r, x[maxn], c[maxn], ans = 1e18;
LL sumx, sumc, sum, totmx, totmn;
LL k, b;
inline char gc(){
static char buf[5000000], *p1 = buf, *p2 = buf;
return (p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, 5000000, stdin), p1 == p2) ? EOF : *p1++;
}
void read(int &x) {
x = 0; static char c = gc();
while(!isdigit(c)) c = gc();
while(isdigit(c)) x = x * 10 + c - '0', c = gc();
}
void ref(LL tl, LL tr) {
l = max(tl, l), r = min(tr, r);
}
void dfs(int u, int p) {
sumx += x[u], sumc += c[u], sum += op[u];
if(x[u] > 0) ref(-c[u], op[u] - c[u]);
else ref(c[u] - op[u], c[u]);
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if(v == p) continue;
if(x[v]) {
k = x[u] + x[v], b = e[i].w - c[u] - c[v];
if(!k) {
if(b) {
printf("NIE");
exit(4);
}
continue;
}
if(b % k != 0) {
printf("NIE");
exit(3);
}
ans = b / k;
continue;
}
x[v] = -x[u];
c[v] = e[i].w - c[u];
dfs(v, u);
}
}
void GetCon(int u) {
x[u] = 1, sum = sumx = sumc = 0;
ans = 1e18, l = 0, r = op[u];
dfs(u, 0);
if(l > r) {
printf("NIE");
exit(4);
}
if(ans != 1e18) {
if(ans < l || ans > r)
{
printf("NIE");
exit(5);
}
l = r = ans;
}
if(sumx > 0) {
totmn += sum - (sumx * r + sumc);
totmx += sum - (sumx * l + sumc);
} else {
totmn += sum - (sumx * l + sumc);
totmx += sum - (sumx * r + sumc);
}
}
int main() {
read(n), read(m);
for(register int i = 1; i <= n; ++i)
read(op[i]);
for(register int i = 1; i <= m; ++i) {
read(u), read(v), read(w);
adde(u, v, w), adde(v, u, w);
}
for(register int i = 1; i <= n; ++i)
if(!x[i]) GetCon(i);
printf("%lld %lld", totmn, totmx);
return 0;
}
rockdu
没有帐号? 立即注册