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

题目大意

给出一个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[N];
int g[N],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[N];
LL k[N],b[N];
LL n_mx,n_mn;
LL n_k,n_b;
int q[N];
 
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;
}
posted @ 2017-02-16 19:57  _zwl  阅读(278)  评论(0编辑  收藏  举报