您的位置:首页 > 其它

bzoj 2801 [Poi2012]Minimalist Security 设一个,求出所有

2017-02-16 19:57 288 查看

题目大意

给出一个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)}的最小值和最大值。

无解输出NIE

分析

可以搞出很多对方程组

\(A+B=C\)

\(0\le A \le p_A\)

\(0\le B \le p_B\)

之类的

由于是一幅图

对于每个连通块

我们设其中一个点为x

其它的所有点都可以用kx+b来表示,k为\(\pm1\)

正样我们可以求出x的取值范围

进而求出最大最小值

注意

x空集NIE

如果便利到一个点已经有k和b

1.k相同,b不同,NIE

2.k不同,直接将x的取值范围确定为一个定值

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=500007;
const int M=3000007;

inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
}

LL mn=0,mx=0;
int n,m;
LL fir
;
int g
,te;
struct edge{int y,next;LL d;}e[M<<1];

void addedge(int x,int y,LL d){
e[++te].y=y;e[te].d=d;e[te].next=g[x];g[x]=te;
}

int vis
;
LL k
,b
;
LL n_mx,n_mn;
LL n_k,n_b;
int q
;

void NIE(){
puts("NIE");
exit(0);
}

void bfs(int bg){
int h=0,t=1,x,p,y;
LL lf,rt;
LL kk,bb;
q[t]=bg;
vis[bg]=1;
while(h^t){
x=q[++h];
n_k+=k[x];
n_b+=b[x];

if(k[x]==-1) lf=b[x]-fir[x],rt=b[x];
else lf=-b[x],rt=fir[x]-b[x];
if(rt<n_mn) NIE();
if(lf>n_mx) NIE();
if(lf>rt) NIE();
n_mn=max(n_mn,lf);
n_mx=min(n_mx,rt);

for(p=g[x];p;p=e[p].next){
y=e[p].y;
if(!vis[y]){
k[y]=-k[x];
b[y]=e[p].d-b[x];
q[++t]=y;
vis[y]=1;
}
else{
kk=-k[x];
bb=e[p].d-b[x];
if(kk==k[y]){
if(bb!=b[y]) NIE();
}
else{
bool rev=0;
if(kk==-1) swap(kk,k[y]),swap(bb,b[y]),rev=1;
if(b[y]-bb<0) NIE();
if((b[y]-bb)&1) NIE();
lf=rt=(b[y]-bb)/2;
if(rt<n_mn) NIE();
if(lf>n_mx) NIE();
if(lf>rt) NIE();
n_mn=max(n_mn,lf);
n_mx=min(n_mx,rt);
if(rev) k[y]=kk,b[y]=bb;
}
}
}
}
}

int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
#endif

int i,x,y,z;
n=rd(),m=rd();

for(i=1;i<=n;i++) fir[i]=rd();

for(i=1;i<=m;i++){
x=rd(),y=rd(),z=rd();
z=fir[x]+fir[y]-z;
addedge(x,y,z);
addedge(y,x,z);
}

for(i=1;i<=n;i++)
if(!vis[i]){
n_mn=0;
n_mx=fir[i];
n_k=0;
n_b=0;
k[i]=1;
b[i]=0;
bfs(i);
if(n_k<0){
mn+=n_mx*n_k+n_b;
mx+=n_mn*n_k+n_b;
}
else{
mn+=n_mn*n_k+n_b;
mx+=n_mx*n_k+n_b;
}
}
printf("%lld %lld\n",mn,mx);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: