Task
给出一个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<=500,000, m<=3,000,000, 0<=p(i)<=10^6, 0<=w<=10^6.
Solution
对于每一条边(u,v):z[u]+z[v]是确定的,也就是确定了端点中的一个,另一个也可以确定了.那么假如确定联通块内任意一点的值,整个联通块都可以确定下来了.
假设设联通块任意一点x的值为a,那么联通块剩下的点k都可以用来y*a+z表示.通过0≤y*a+z≤p[k]求出a的范围.对于这个联通块,求出∑z[k]关于a的表达式,利用a的范围求出最值.
只要遍历一遍图即可,复杂度O(m+n).
当然还有一种做法,通过并查集,维护每个点到它所在树根(假设树根的值为a)的表达式:ya+z.
每次对一条边(u,v):
假如u,v已经联通,可以直接求出a的值.
否则合并两棵树.
//对于并查集的做法,需要计算的地方有点多不易调试,比赛时最好选取第一种做法.
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#include<iostream>
using namespace std;
const int M=5e5+5;
int head[M],rt,ec=0,f[M],n,p[M],flag=1,tot,A=0,m;
ll val[M];
ll mx=0,mi=0,L,R,B=0;
struct node{
int to,v,nex;
}e[M*12];
inline void rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c>=48);
}
void ins(int a,int b,int c){
e[ec]=(node){b,c,head[a]};
head[a]=ec++;
e[ec]=(node){a,c,head[b]};
head[b]=ec++;
}
bool dfs(int x,int par){
ll a=(p[x]-val[x])/f[x],b=-val[x]/f[x];
//0<=f[x]*a+val[x]<=p[x]
//a<=p[x]-val[x]/f[x]
//a>=-val[x]/f[x]
A+=f[x];
B+=val[x];
if(f[x]>0)L=max(L,b),R=min(R,a);
else L=max(L,a),R=min(R,b);
if(L>R)return false;
for(int i=head[x];~i;i=e[i].nex){
int to=e[i].to,v=e[i].v;//
if(to==par)continue;
ll t=v-val[x];
if(f[to]!=0){
if(f[to]==-f[x]&&val[to]!=t)return false;
else if(f[to]!=-f[x]){
if((val[to]-t)%(-f[x]-f[to])!=0)return false;
ll res=(val[to]-t)/(-f[x]-f[to]);
L=max(L,res);//f[to]+val[to]=f[x]+val[x]
R=min(R,res);
if(L>R)return false;
}
}
else{
f[to]=-f[x];
val[to]=t;
if(!dfs(to,x)){return false;}
}
}
return true;
}
bool solve(){
for(int i=1;i<=n;i++){
if(f[i]==0){
L=-1e18,R=1e18;
A=B=0;
f[i]=1;
val[i]=0;
if(!dfs(i,i))return false;
ll a=L*A+B,b=R*A+B;
mi+=min(a,b);
mx+=max(a,b);
}
}
return true;
}
int main(){
memset(head,-1,sizeof(head));
int i,j,a,b,c;
rd(n);rd(m);
for(i=1;i<=n;i++)rd(p[i]);
for(i=1;i<=m;i++){
rd(a);rd(b);rd(c);
ins(a,b,p[a]+p[b]-c);
}
if(!solve())puts("NIE");
else cout<<mi<<" "<<mx<<endl;
return 0;
}
并查集:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<bitset>
#define ll long long
#define lsy puts("lay")
#define rep(i,a,b) for((i)=(a);(i)<=(b);(i)++)
#define per(i,a,b) for((i)=(b);(i)>=(a);(i)--)
using namespace std;
inline void rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c>=48);
}
inline void print(int k){
if(!k)return;
print(k/10);
putchar(k%10^48);
}
inline void sc(int k){
if(k<0){k=-k;putchar('-');}
print(k);
if(k==0)putchar('0');
// putchar('\n');
}
inline void Max(int &x,int y){if(x<y)x=y;}
inline void Min(int &x,int y){if(x>y)x=y;}
const int maxn=500005;
const int maxm=3000005;
int u[maxm],v[maxm],e[maxm],fa[maxn],f[maxn],n,m,h[maxn],p[maxn];
ll mi=0,mx=0,sum[maxn],rt[maxn],val[maxn],l[maxn],r[maxn];
int get(int x){
if(fa[x]!=x){
int a=f[x],b=fa[x];
fa[x]=get(fa[x]);
val[x]=val[b]*a+val[x];
f[x]=f[b]*a;
}
return fa[x];
}
bool solve(){
int i,j,k,a,b,c;
ll d,t;
for(i=1;i<=m;i++){
a=get(u[i]),b=get(v[i]);
if(a!=b){
val[b]=f[v[i]]*(-val[u[i]]+e[i]-val[v[i]]);
f[b]=-f[u[i]]*f[v[i]];
fa[b]=a;
if(~rt[b]){//rt[b]=rt[a]*f[b]+val[b]
c=(rt[b]-val[b])*f[b];
if(~rt[a]&&rt[a]!=c) return false;
rt[a]=c;
}
continue;
}
c=f[u[i]]+f[v[i]];
d=e[i]-(val[u[i]]+val[v[i]]);//c*rt=d
if(c!=0&&d%c!=0){return false;}
if(c){
t=d/c;
if(rt[a]==-1)rt[a]=t;
else if(rt[a]!=t){
return false;
}
}
}
for(i=1;i<=n;i++)l[i]=0,r[i]=p[i];
for(i=1;i<=n;i++){
a=get(i);//0<=f[i]*rt+val[i]<=p[i]'
if(f[i]>0){//rt<=p[i]-val[i]
r[a]=min(r[a],p[i]-val[i]);
l[a]=max(l[a],-val[i]);
}
else {//0<=-rt+val[i]<=p[i]
r[a]=min(r[a],val[i]);
l[a]=max(l[a],val[i]-p[i]);
}
h[a]+=f[i];
sum[a]+=val[i];
}
for(i=1;i<=n;i++){
if(fa[i]==i){
a=i;
if(l[a]>r[a]){
return false;
}if(~rt[a]){
if(rt[a]>r[a]||rt[a]<l[a]){
return false;}
mi+=rt[a]*h[a]+sum[a],mx+=rt[a]*h[a]+sum[a];
}
else {
ll b=h[a]*l[a]+sum[a],c=h[a]*r[a]+sum[a];
mi+=min(b,c);mx+=max(b,c);
}
}
}
return true;
}
int main(){
int i,j,k;
memset(rt,-1,sizeof(rt));
memset(val,0,sizeof(val));
rd(n);rd(m);
for(i=1;i<=n;i++){
fa[i]=i,rd(p[i]);
f[i]=1;
}
for(i=1;i<=m;i++){
rd(u[i]);rd(v[i]);rd(e[i]);
e[i]=p[u[i]]+p[v[i]]-e[i];
}
if(!solve())puts("NIE");
else cout<<mi<<" "<<mx<<endl;
return 0;
}