一张n个点m条边的无向图,有点权有边权都是非负,且每条边的权值小于等于两个顶点的权值和,现在要将每个点减一个非负整数使得每条边权等于两个顶点的点权和,问最大修改代价和最小修改代价

思路神的一匹,完全想不出来,对着题解想了半天才有点理解

首先有一个小结论:对于一个联通块,如果一个顶点的值确定了,其余顶点的值都能确定。这是显然的,因为直接用一条边的边权减去已知点权就是另一个点的权值。如果我们设一个点的权值为x,与之相连的边权为w,另一点点权即为w-x

这样的话其实整个联通块内所有的点权都可以表示成y=k*x+b(k∈(-1,1))的形式,我们对于解一下关于y的不等式即可

特别注意的是,如果图中存在奇环,那么某个点会存在两种系数不同的表示,这时我们直接解这个方程就可以求出x的唯一解

这时我们还得保证x解出来为整数,这也是做这个题目要注意的的一点

代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdlib>
#define N 300010
#define M 5000010
#define ll long long
using namespace std;
queue<int>qx,qy; int n,m,num;
int head[N],val[N],q[N];
bool vis[N][];
ll ans1,ans2,v[N][]; int read()
{
char ch=getchar(); int f=,x=;
while(ch>''||ch<'') {if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
return x*f;
} struct point{
int next,to,dis;
}e[M<<]; void add(int from,int to,int dis)
{
e[++num].next=head[from];
e[num].to=to;
e[num].dis=dis;
head[from]=num;
} void bfs(int x)
{
vis[x][]=;
qx.push(x); qy.push();
int tot=; q[++tot]=x;
while(!qx.empty())
{
int a=qx.front(),b=qy.front();
qx.pop(); qy.pop();
for(int i=head[a];i;i=e[i].next)
{
int to=e[i].to;
if(!vis[to][]&&!vis[to][]) q[++tot]=to;
if(vis[to][b^])
{
if(v[to][b^]!=e[i].dis-v[a][b]) {printf("NIE"); exit();}
}
else
{
vis[to][b^]=,v[to][b^]=e[i].dis-v[a][b];
qx.push(to); qy.push(b^);
}
}
}
ll L=,R=val[x],sum1=,sum2=;
for(int i=;i<=tot;i++)
{
int a=q[i];
if(vis[a][]) L=max(L,-v[a][]),R=min(R,val[a]-v[a][]);
if(vis[a][]) L=max(L,v[a][]-val[a]),R=min(R,v[a][]);
if(vis[a][]&&vis[a][])
{
if((v[a][]-v[a][])&) {printf("NIE"); exit();}
L=max(L,(v[a][]-v[a][])>>);
R=min(R,(v[a][]-v[a][])>>);
}
}
if(L>R) {printf("NIE"); exit();}
for(int i=;i<=tot;i++)
{
int a=q[i];
if(vis[a][]) sum1+=val[a]-L-v[a][],sum2+=val[a]-R-v[a][];
else sum1+=val[a]+L-v[a][],sum2+=val[a]+R-v[a][];
}
if(sum1>sum2) swap(sum1,sum2);
ans1+=sum1,ans2+=sum2;
} int main()
{
n=read(); m=read();
for(int i=;i<=n;i++) val[i]=read();
for(int i=;i<=m;i++)
{
int x=read(),y=read(),z=read();
add(x,y,z); add(y,x,z);
}
for(int i=;i<=n;i++)
if(!vis[i][]&&!vis[i][])
bfs(i);
printf("%lld %lld",ans1,ans2);
return ;
}

最新文章

  1. MS SQL SERVER导出表结构到Excel
  2. php 调用系统命令
  3. BZOJ4584 : [Apio2016]赛艇
  4. 第一天 Linux 是什么
  5. Linux top和负载的说明
  6. 构建基于WinRT的WP8.1 App 03:Page控件
  7. C4.5决策树算法概念学习
  8. Qt绘图控件qwt绘制等比例坐标图
  9. 三个重要的游标sp_cursoropen
  10. C. Robot(BFS)
  11. nmap -- write a nmap script
  12. Cocos性能优化工具的开发介绍Visual Studio内存泄漏检测工具——Visual Leak Detector
  13. CENTOS/RHEL 7 系统中设置SYSTEMD SERVICE的ULIMIT资源限制
  14. Nginx配置文件nginx.conf中文详解(转)
  15. Hibernate设置时间戳的默认值和更新时间的自动更新
  16. cookies,sessionstorage,localstorage的区别?
  17. CentOS使用systemctl daemon-reload报错Error getting authority: Error initializing authority: Error calling StartServiceByName for org.freedesktop.PolicyKit1: Timeout was reached (g-io-error-quark, 24)解决办法
  18. Oracle 11.2.0.4 For Windows 64bit+32bit 数据库
  19. SQL 一对多联表查询最大值
  20. ios中键盘处理源码

热门文章

  1. 对IOS设备中UDID的一些思考
  2. python 之re模块(正则表达式) 分组、断言详解
  3. IOS 预览pdf,word文档的集中方式
  4. [LintCode] 合并排序数组II
  5. HttpURLConnection 当作请求调用接口不带返回参数的工具类
  6. MD5-【验签】
  7. CodeForeces 665C Simple Strings
  8. 1 duilib 自绘标题 最大化图标显示bug ----WindowImplBase的bug
  9. 微信公众号 待发货-物流中-已收货 foreach break continue
  10. FastReports_4.14.1 _Cliff手动安装