• 【BZOJ2801】[Poi2012]Minimalist Security BFS


    【BZOJ2801】[Poi2012]Minimalist Security

    Description

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

    Input

    第一行两个正整数n,m (n<=500,000, m<=3,000,000)。
    第二行n个整数,依次表示p(1),p(2),...,p(n) (0<=p(i)<=10^6)。
    下面m行,每行三个整数u,v,w (1<=u,v<=n, 0<=w<=10^6),表示存在一条权值为w的边(u,v)。

    Output

    两个正整数,分别表示sum{z(i)}的最小值和最大值,如果不存在方案就输出NIE。

    Sample Input

    For the input data:
    3 2
    5 10 5
    1 2 5
    2 3 3
    the correct result is:
    12 15
    whereas for the following input data:
    3 3
    1 1 1
    1 2 1
    1 3 1
    3 2 1
    the correct result is:
    NIE

    题解:容易发现,对于一个连通块,只需要任意确定一个点的值,其它的点就都确定了。所以我们设这个点为x,那么其他点的值都是x+d或-x+d的形式,我们BFS一下即可得到,然后就是特判部分了:

    当我们搜到了一个点时,先算一下那个点的系数即常数项,如果这个点在之前已经被搜过了,且系数一样,那么直接看常数项,如果相同则不用管,不同则无解;如果系数不一样,那么我们已经得到了一个等式,x值就是唯一确定的了(前提是下面↓的不等式有解)。

    如果没有出现上述情况,那么我们已经将连通块中的所有点都用x表示了出来,并且这些点都要满足值$in [0,P]$,我们就相当于得到了若干个不等式,求出不等式的解就能得到x的取值范围。如果无解则NIE;否则,这整个连通块的权值之和一定是关于x的一次函数,它的极值一定在x为极值时取到,分别计算一下即可。

    此题还需要读入优化。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <cstdlib>
    using namespace std;
    const int maxn=500010;
    const int maxm=3000010;
    typedef long long ll;
    int n,m,cnt,tot;
    ll ans1,ans2,L,R,sum1,sum2;
    int to[maxm<<1],next[maxm<<1],head[maxn],val[maxm<<1],p[maxn],vis[maxn][2],q[maxn];
    ll v[maxn][2];
    queue<int> qx,qy;
    inline char nc()
    {
    	static char buf[100000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=nc();
    	while(!isdigit(gc))	{if(gc=='-')	f=-f;	gc=nc();}
    	while(isdigit(gc))	ret=ret*10+(gc^'0'),gc=nc();
    	return ret*f;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    void bfs(int x)
    {
    	vis[x][0]=1;
    	qx.push(x),qy.push(0);
    	int i,a,b;
    	q[tot=1]=x;
    	while(!qx.empty())
    	{
    		a=qx.front(),b=qy.front(),qx.pop(),qy.pop();
    		for(i=head[a];i!=-1;i=next[i])
    		{
    			if(!vis[to[i]][0]&&!vis[to[i]][1])	q[++tot]=to[i];
    			if(vis[to[i]][b^1])
    			{
    				if(v[to[i]][b^1]!=val[i]-v[a][b])	printf("NIE"),exit(0);
    			}
    			else
    			{
    				vis[to[i]][b^1]=1,v[to[i]][b^1]=val[i]-v[a][b];
    				qx.push(to[i]),qy.push(b^1);
    			}
    		}
    	}
    	L=0,R=p[x],sum1=sum2=0;
    	for(i=1;i<=tot;i++)
    	{
    		a=q[i];
    		if(vis[a][0])	L=max(L,-v[a][0]),R=min(R,p[a]-v[a][0]);
    		if(vis[a][1])	L=max(L,v[a][1]-p[a]),R=min(R,v[a][1]);
    		if(vis[a][0]&&vis[a][1])
    		{
    			if((v[a][1]-v[a][0])&1)	printf("NIE"),exit(0);
    			L=max(L,(v[a][1]-v[a][0])>>1),R=min(R,(v[a][1]-v[a][0])>>1);
    		}
    	}
    	if(L>R)	printf("NIE"),exit(0);
    	for(i=1;i<=tot;i++)
    	{
    		a=q[i];
    		if(vis[a][0])	sum1+=p[a]-L-v[a][0],sum2+=p[a]-R-v[a][0];
    		else	sum1+=p[a]+L-v[a][1],sum2+=p[a]+R-v[a][1];
    	}
    	if(sum1>sum2)	swap(sum1,sum2);
    	ans1+=sum1,ans2+=sum2;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b,c;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=n;i++)	p[i]=rd();
    	for(i=1;i<=m;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
    	for(i=1;i<=n;i++)	if(!vis[i][0]&&!vis[i][1])	bfs(i);
    	printf("%lld %lld
    ",ans1,ans2);
    	return 0;
    }
  • 相关阅读:
    Word 操作类库
    Windows服务卸载之后未重启机器之前再安装问题
    Word转Html
    Centos7下配置Python3和Python2共存,以及对应版本Ipython安装配置
    Linux 和Windows之间命令行实现目录或文件互传
    centos下卸载OpenJDK 并安装sun的jdk
    bridged(桥接模式)、NAT(网络地址转换模式)和hostonly(主机模式)VMware下三种网络配置方式
    关于centos启动报错:Failed to start Crash recovery kernel arming的解决方案
    centos7下固定IP(静态IP)网络配置
    【分享】BUG从诞生到灭亡——处理BUG的流程
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7813355.html
Copyright © 2020-2023  润新知