[BZOJ 2801]POI2012 Minimalist Security

来源:互联网 发布:python 3.0 廖雪峰 编辑:程序博客网 时间:2024/04/29 20:59

首先不要被题目吓倒,这题你就做出大半了。

只有联通块内才会互相约束(废话)

扫描每一个联通块,找到一个起点,假设他的权值为x。

那么每个连出去的边的终点权值为  w-x 。也就是说每个点上一定为kx+b(其中k=1或-1)

也许每个点会被扫描到多次,分以下几种情况

1、k1==k2,若b1!=b2无解,若b1==b2.......没有影响,继续running

2、k1!=k2,那么我们可以算出x的值,把这个值带入算出连通块里的点的值,判断有无解即可。

如果扫描途中没有遇到什么意外(就是1、2的情况)那么利用么个点i的不等式连立不等式组0<=ki x+bi<=pi解出x的范围

注意解集是否为空集,这里也可能出现无解。

最后我们可以看到代价是x的一次函数,也就是说最值在边界出取得,判断一下就好了。

复杂度O(n+m)

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const int Maxn=6000005, Max=500005;int node[Maxn],next[Maxn],a[Max],q[Max],x,y,z,n,m,l,r,tot,i;LL len[Maxn],dig[Max],w[Max],total,maxx,minx,cnt1,cnt2,dw,up,data,t;bool v[Max],flag;struct arr { int w,s; } d[Max],tmp;int read(){  char ch=getchar();  int ret=0;  while (ch<'0' || ch>'9') ch=getchar();  while (ch>='0' && ch<='9')    {ret=ret*10+ch-'0'; ch=getchar();}  return ret;}void add(int x,int y,int z){  node[++tot]=y; next[tot]=a[x]; a[x]=tot; len[tot]=z;  node[++tot]=x; next[tot]=a[y]; a[y]=tot; len[tot]=z;}bool Judge(int x){  for (q[l=r=1]=x,total=0;l<=r;l++){  v[q[l]]=1;  if (dig[q[l]]<0 || dig[q[l]]>w[q[l]]) return 0;  total+=(LL)w[q[l]]-dig[q[l]];  for (int i=a[q[l]];i;i=next[i]){    if (dig[node[i]]==-1)    dig[ q[++r]=node[i] ]=len[i]-dig[ q[l] ];  else if (dig[q[l]]+dig[node[i]]!=len[i])    return 0;    }  }  return 1;}void bfs(int x){  d[x].w=0; d[x].s=1; v[x]=1;  for (q[l=r=1]=x,data=-1;l<=r;l++){    for (int i=a[q[l]];i;i=next[i]){    if (v[node[i]]){        tmp.w=len[i]-d[node[i]].w;    tmp.s=(d[node[i]].s^1);    if (tmp.s==d[q[l]].s){      if (tmp.w!=d[q[l]].w)        {flag=0; break;}      else continue;    } else    {      if (tmp.s==0) t=-1; else t=1;      if ( (d[q[l]].w-tmp.w)/t<0 ) {flag=0; break;}      if ( ( (d[q[l]].w-tmp.w)/t )%2!=0 ) {flag=0; break;}        else {data = (d[q[l]].w-tmp.w)/t/2; break;}    }        } else    {    d[node[i]].w=len[i]-d[q[l]].w;    d[node[i]].s=(d[q[l]].s^1);    v[q[++r]=node[i]]=1;    }        }        if (flag==0 || data>=0) break;  }    if (data>=0){  dig[x]=data;  if (Judge(x)){    minx+=total;    maxx+=total;  } else {flag=0;return;}  return;  }  if (flag==0) return;  dw=0; up=1000000000;  for (int i=1;i<=r;i++){  tmp=d[q[i]];  if (tmp.s==1){  up=min(up,(LL)w[q[i]]-tmp.w);  dw=max(dw,(LL)-tmp.w);    } else{  up=min(up,(LL)tmp.w);  dw=max(dw,(LL)tmp.w-w[q[i]]);    }  }  if (up<dw){ flag=0; return; }  cnt1=cnt2=0;  for (int i=1;i<=r;i++){  if (d[q[i]].s==1){    cnt1+=(LL)w[q[i]]-(d[ q[i] ].w+dw);    cnt2+=(LL)w[q[i]]-(d[ q[i] ].w+up);    } else    {      cnt1+=(LL)w[q[i]]-(d[ q[i] ].w-dw);    cnt2+=(LL)w[q[i]]-(d[ q[i] ].w-up);    }  }  minx+=min(cnt1,cnt2);  maxx+=max(cnt1,cnt2);}int main(){  freopen("bez.in","r",stdin);  freopen("bez.out","w",stdout);  //scanf("%d%d",&n,&m);  n=read(); m=read();  for (i=1;i<=n;i++) w[i]=read(); //scanf("%d",&w[i]);  for (i=1;i<=m;i++){  //scanf("%d%d%d",&x,&y,&z);  x=read(); y=read(); z=read();  add(x,y,z);  }  memset(dig,-1,sizeof(dig));  for (i=1,flag=1;i<=n;i++)  if (!v[i]){    bfs(i);    if (flag==0) break;  }  if (flag==0) puts("NIE");   else printf("%I64d %I64d\n",minx,maxx);  return 0;}


0 0