一张n个点m条边的无向图,有点权有边权都是非负,且每条边的权值小于等于两个顶点的权值和,现在要将每个点减一个非负整数使得每条边权等于两个顶点的点权和,问最大修改代价和最小修改代价
思路神的一匹,完全想不出来,对着题解想了半天才有点理解
首先有一个小结论:对于一个联通块,如果一个顶点的值确定了,其余顶点的值都能确定。这是显然的,因为直接用一条边的边权减去已知点权就是另一个点的权值。如果我们设一个点的权值为x,与之相连的边权为w,另一点点权即为w-x
这样的话其实整个联通块内所有的点权都可以表示成y=k*x+b(k∈(-1,1))的形式,我们对于解一下关于y的不等式即可
特别注意的是,如果图中存在奇环,那么某个点会存在两种系数不同的表示,这时我们直接解这个方程就可以求出x的唯一解
这时我们还得保证x解出来为整数,这也是做这个题目要注意的的一点
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<cstdlib> 6 #define N 300010 7 #define M 5000010 8 #define ll long long 9 using namespace std; 10 queue<int>qx,qy; 11 12 int n,m,num; 13 int head[N],val[N],q[N]; 14 bool vis[N][2]; 15 ll ans1,ans2,v[N][2]; 16 17 int read() 18 { 19 char ch=getchar(); int f=1,x=0; 20 while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();} 21 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 22 return x*f; 23 } 24 25 struct point{ 26 int next,to,dis; 27 }e[M<<1]; 28 29 void add(int from,int to,int dis) 30 { 31 e[++num].next=head[from]; 32 e[num].to=to; 33 e[num].dis=dis; 34 head[from]=num; 35 } 36 37 void bfs(int x) 38 { 39 vis[x][0]=1; 40 qx.push(x); qy.push(0); 41 int tot=0; q[++tot]=x; 42 while(!qx.empty()) 43 { 44 int a=qx.front(),b=qy.front(); 45 qx.pop(); qy.pop(); 46 for(int i=head[a];i;i=e[i].next) 47 { 48 int to=e[i].to; 49 if(!vis[to][0]&&!vis[to][1]) q[++tot]=to; 50 if(vis[to][b^1]) 51 { 52 if(v[to][b^1]!=e[i].dis-v[a][b]) {printf("NIE"); exit(0);} 53 } 54 else 55 { 56 vis[to][b^1]=1,v[to][b^1]=e[i].dis-v[a][b]; 57 qx.push(to); qy.push(b^1); 58 } 59 } 60 } 61 ll L=0,R=val[x],sum1=0,sum2=0; 62 for(int i=1;i<=tot;i++) 63 { 64 int a=q[i]; 65 if(vis[a][0]) L=max(L,-v[a][0]),R=min(R,val[a]-v[a][0]); 66 if(vis[a][1]) L=max(L,v[a][1]-val[a]),R=min(R,v[a][1]); 67 if(vis[a][0]&&vis[a][1]) 68 { 69 if((v[a][1]-v[a][0])&1) {printf("NIE"); exit(0);} 70 L=max(L,(v[a][1]-v[a][0])>>1); 71 R=min(R,(v[a][1]-v[a][0])>>1); 72 } 73 } 74 if(L>R) {printf("NIE"); exit(0);} 75 for(int i=1;i<=tot;i++) 76 { 77 int a=q[i]; 78 if(vis[a][0]) sum1+=val[a]-L-v[a][0],sum2+=val[a]-R-v[a][0]; 79 else sum1+=val[a]+L-v[a][1],sum2+=val[a]+R-v[a][1]; 80 } 81 if(sum1>sum2) swap(sum1,sum2); 82 ans1+=sum1,ans2+=sum2; 83 } 84 85 int main() 86 { 87 n=read(); m=read(); 88 for(int i=1;i<=n;i++) val[i]=read(); 89 for(int i=1;i<=m;i++) 90 { 91 int x=read(),y=read(),z=read(); 92 add(x,y,z); add(y,x,z); 93 } 94 for(int i=1;i<=n;i++) 95 if(!vis[i][0]&&!vis[i][1]) 96 bfs(i); 97 printf("%lld %lld",ans1,ans2); 98 return 0; 99 }
扫描二维码关注公众号,回复:
2893454 查看本文章