题目大意:一张n个点m条边的无向图,有点权有边权都是非负,且每条边的权值小于等于两个顶点的权值和,现在要将每个点减一个非负整数使得每条边权等于两个顶点的点权和,问最大修改代价和最小修改代价
首先对于每一个连通块假如确定了一个点的值,那么所有其他点的权值就都确定了
所以部门可以随便找到一个点设他的权值是x,然后把其他点全部用x表示出来,这样同时根据这个点的修改上限为x圈定一个取值范围,这样就可以判断合不合法了
然后在合法范围内求最大值和最小值就可以了
这题强制用读入优化,直接用scanf会RE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define N 500010
#define M 6000010
using namespace std;
char BB[1<<15],*K=BB,*T=BB;
#define getc() (K==T&&(T=(K=BB)+fread(BB,1,1<<15,stdin),K==T)?0:*K++)
inline long long read()
{
long long x=0;char ch=getc();
while(ch<'0'||ch>'9')ch=getc();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getc();
return x;
}
long long a[N];
bool used[N];
long long to[M],nxt[M],w[M],pre[N],cnt;
void ae(long long ff,long long tt,long long ww)
{
cnt++;
to[cnt]=tt;
nxt[cnt]=pre[ff];
pre[ff]=cnt;
w[cnt]=ww;
}
long long o[N],v[N];
long long q[N],h,t;
long long MIN,MAX;
void solve(long long S,long long &tmp1,long long &tmp2)
{
h=t=1;q[1]=S;o[S]=1;v[S]=0;
long long O=0,V=0;
used[S]=true;
MIN=0;MAX=a[S];
long long i,j,x,y;
while(h<=t)
{
x=q[h];h++;
O+=-o[x];V+=a[x]-v[x];
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(!used[j])
{
used[j]=true;
t++;q[t]=j;
o[j]=-o[x];
v[j]=w[i]-v[x];
if(o[j]==1)
{
MAX=min(MAX,a[j]-v[j]);
MIN=max(MIN,-v[j]);
}
else
{
MAX=min(MAX,v[j]);
MIN=max(MIN,v[j]-a[j]);
}
if(MIN>MAX)
{
puts("NIE");
exit(0);
}
}
else
{
if(o[j]==o[x])
{
if((v[j]+v[x]-w[i])%2!=0)
{
puts("NIE");
exit(0);
}
else
{
MAX=min(MAX,(w[i]-v[x]-v[j])/2/o[x]);
MIN=max(MIN,(w[i]-v[x]-v[j])/2/o[x]);
if(MIN>MAX)
{
puts("NIE");
exit(0);
}
}
}
else
{
if(w[i]!=v[x]+v[j])
{
puts("NIE");
exit(0);
}
}
}
}
}
if(O>0) tmp1+=MIN*O+V,tmp2+=MAX*O+V;
else tmp1+=MAX*O+V,tmp2+=MIN*O+V;
}
int main()
{
long long n,m;
n=read();m=read();
long long i,j,x,y,z;
for(i=1;i<=n;i++)
a[i]=read();
for(i=1;i<=m;i++)
{
x=read();y=read();z=read();
ae(x,y,z);ae(y,x,z);
}
long long minn=0,maxn=0;
for(i=1;i<=n;i++)
if(!used[i])
solve(i,minn,maxn);
printf("%lld %lld",minn,maxn);
}