【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
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:
题解:容易发现,对于一个连通块,只需要任意确定一个点的值,其它的点就都确定了。所以我们设这个点为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\n",ans1,ans2);
return 0;
}
【BZOJ2801】[Poi2012]Minimalist Security BFS的更多相关文章
- 【BZOJ2791】[Poi2012]Rendezvous 倍增
[BZOJ2791][Poi2012]Rendezvous Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组 ...
- 【BZOJ2792】[Poi2012]Well 二分+双指针法
[BZOJ2792][Poi2012]Well Description 给出n个正整数X1,X2,...Xn,可以进行不超过m次操作,每次操作选择一个非零的Xi,并将它减一. 最终要求存在某个k满足X ...
- 【BZOJ2797】[Poi2012]Squarks 暴力乱搞
[BZOJ2797][Poi2012]Squarks Description 设有n个互不相同的正整数{X1,X2,...Xn},任取两个Xi,Xj(i≠j),能算出Xi+Xj.现在所有取法共n*(n ...
- 【BZOJ2793】[Poi2012]Vouchers 调和级数
[BZOJ2793][Poi2012]Vouchers Description 考虑正整数集合,现在有n组人依次来取数,假设第i组来了x人,他们每个取的数一定是x的倍数,并且是还剩下的最小的x个.正整 ...
- 【BZOJ2799】[Poi2012]Salaries 乱搞
[BZOJ2799][Poi2012]Salaries Description 给出一棵n个结点的有根树,结点用正整数1~n编号.每个结点有一个1~n的正整数权值,不同结点的权值不相同,并且一个结点的 ...
- 【BZOJ2803】[Poi2012]Prefixuffix 结论题
[BZOJ2803][Poi2012]Prefixuffix Description 对于两个串S1.S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同.例如串ababba和串 ...
- 【BZOJ2794】[Poi2012]Cloakroom 离线+背包
[BZOJ2794][Poi2012]Cloakroom Description 有n件物品,每件物品有三个属性a[i], b[i], c[i] (a[i]<b[i]).再给出q个询问,每个询问 ...
- 【BZOJ2790】[Poi2012]Distance 筛素数+调和级数
[BZOJ2790][Poi2012]Distance Description 对于两个正整数a.b,这样定义函数d(a,b):每次操作可以选择一个质数p,将a变成a*p或a/p, 如果选择变成a/p ...
- 【BZOJ3060】[Poi2012]Tour de Byteotia 并查集
[BZOJ3060][Poi2012]Tour de Byteotia Description 给定一个n个点m条边的无向图,问最少删掉多少条边能使得编号小于等于k的点都不在环上. Input ...
随机推荐
- atitit.资源释放机制--attilax总结
atitit.资源释放机制--attilax总结 1. .全手工, 1 2. 引用计数, 1 2.1. 成本也显而易见. 1 2.2. 循环引用的问题, 2 2.3. 引用计数方式事实上也有经典的卡顿 ...
- java遍历实体类的属性和数据类型以及属性值
遍历实体类的树形和数据类型一级属性值 /** * 遍历实体类的属性和数据类型以及属性值 * @param model * @throws NoSuchMethodException * @throws ...
- Oracle宣布很多其它的Java 9 新特性
随着Oracle确认了其余的4个Java 9特性,下一代Java的计划開始变得更清晰了,Oracle已经发布了第二套Java 9特性.自从Oracle在今年早些时候宣布了3个新的API和模块化源代码后 ...
- Android实战简易教程-第二十三枪(基于Baas的用户注冊验证username是否反复功能!)
接上一篇,加入验证用户名是否已经注冊功能! 仅仅须要改动MainActivity.java: package com.example.logintest; import java.util.List; ...
- UVA 146 ID Codes(下一个排列)
C - ID Codes Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Submit Statu ...
- PKI/CA
PKI( Public Key Infrastructure )指的是公钥基础设施. CA ( Certificate Authority )指的是认证中心. PKI从技术上解决了网络通信安全的种种障 ...
- angular路由介绍
AngularJS路由功能是一个纯前端的解决方案,与我们熟悉的后台路由不太一样.后台路由,通过不同的URL会路由到不同的控制器上(controller),再渲染(render)到页面(HTML).An ...
- mysql 从一个表中查询插入另一个表
insert into dnt_userfields (uid,realname ) select uid,nickname from discuz.dnt_users where uid>72 ...
- c#第一个程序-计算平方根
上课教的内容.做笔记了. using System; using System.Collections.Generic; using System.ComponentModel; using Syst ...
- Unix系统编程()发送信号的其他方式:raise和killpg
有时,进程需要向自身发送信号,raise 函数就执行了这一任务. #include <signal.h> int raise(int sig); 在单线程程序中,调用raise相当于对ki ...