化下题面给的式子: \(z_u+z_v=p_u+p_v-b_{u,v}\)
发现\(p_u+p_v-b_{u,v}\)是确定的,所以只要确定了一个点\(i\)的权值\(x_i\),和它在同一个联通块的所有点\(j\)的权值\(x_j\)都确定下来了,并且那些点的权值都可以用\((k_jz_i+b_j(k_j\in \{-1,1\})\)来表示。因此一个联通块的答案\(ans\)为:\[z_i\Sigma {k_j}+\Sigma{b_j}\]
然后因为限制了\(0\le z_j \le p_j\),所以把所有\(x_j\)用\(x_i\)表示出来可以得到一个不等式组。解出来\(z_i\)的极值可以对应到\(ans\)的极值了。
代码:
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define inf 100000000
#define N 500005
using namespace std;
int p[N],b[N],k[N],cnt=0,head[N],mn,mx;
bool vis[N];
ll ans1=0,ans2=0,K,B;
struct ed{
int v,w,nxt;
}e[N*20];
inline 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;
}
inline void read(int &y){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
y=x;
}
void dfs(int u,int fa){
//0<= k*x+b <=p_u
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){
puts("NIE");
exit(0);
}
for(register 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]){//偶环判无解,k相等,b相等
puts("NIE");
exit(0);
} else{
if(k[to]==k[u]){//奇环可以解出xi的值,代入看范围
//k1*xi+b1=k2*xi+b2
if((b[to]-tmp)%(-2*k[u])!=0){//权值非整数
puts("NIE");
exit(0);
}
mn=max(mn,(b[to]-tmp)/(-2*k[u]));
mx=min(mx,(b[to]-tmp)/(-2*k[u]));
if(mn>mx){
puts("NIE");
exit(0);
}
}
}
} else{
vis[to]=1;
k[to]=-k[u];
b[to]=tmp;
dfs(to,u);
}
}
}
}
int main(){
register int n,m,u,v,w,i;
read(n),read(m);
for(i=1;i<=n;++i) read(p[i]);
for(i=1;i<=m;++i){
read(u),read(v),read(w);
add(u,v,p[u]+p[v]-w);
}
for(i=1;i<=n;++i){
if(!vis[i]){
vis[i]=1;
K=B=0;
k[i]=1,b[i]=0;
mx=inf,mn=-inf;
dfs(i,0);
ans1+=min(1ll*mn*K+B,1ll*mx*K+B);
ans2+=max(1ll*mn*K+B,1ll*mx*K+B);
}
}
printf("%lld %lld",ans1,ans2);
}