Description
你是申国的一个地方长官,你手下有n个城市。
为了加强基础设施建设,在2020全面建成小康社会,统筹推进经济建设、政治建设、文化建设、社会建设、生态文明建设,坚定实施科教兴国战略、人才强国战略、创新驱动发展战略、乡村振兴战略、区域协调发展战略、可持续发展战略、军民融合发展战略,突出抓重点、补短板、强弱项,特别是要坚决打好防范化解重大风险、精准脱贫、污染防治的攻坚战,使全面建成小康社会得到人民认可、经得起历史检验。你认为本省的水利调配非常有问题,这导致部分地区出现严重的缺水,而部分地区却全年洪灾泛滥。
于是你打算将原有的但是已经废弃了的m条水管重新使用。第i条水管连接城市xi和yi。这些水管联通了所有城市。每座城市对水的需求不同设为ai,部分城市处于缺水状态,ai为正,缺水量刚好为ai mol。部分城市因为有水库,ai为负,它需要向外输送-ai mol的水才能不形成洪灾。对于每条水管,你需要决定它的输送量fi,若fi为正则表示从xi向yi输送fi mol的水,fi为负则表示从yi向xi输送-fi mol的水。
你需要做到每个城市都刚好满足它的需求,即缺ai mol水的城市需要刚好输入ai的水,而多出-ai mol水的城市需要刚好输出-ai mol水。
你需要判断能否满足要求,若满足,你还需要输出所有的f。
题解
判断是否合法很简单,
就是看看a的和是否为0。
现在考虑如何构造出一种合法解。
一种很简单的方法就是先构造一棵生成树,
强制只用树上面的边,这样就可以轻松求出一组合法解。
code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 300003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
int w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
int n,m,x,y,f[N],nxt[N*2],to[N*2],id[N*2],lst[N],tot,a[N];
ll s,v[N],ans[N];
int get(int x){return f[x]=(f[x]==x?x:get(f[x]));}
void ins(int x,int y,int z)
{
nxt[++tot]=lst[x];
to[tot]=y;
id[tot]=z;
lst[x]=tot;
}
void dfs(int x,int fa)
{
v[x]=a[x];
for(int i=lst[x];i;i=nxt[i])
if(to[i]^fa)
{
dfs(to[i],x);
v[x]=v[x]+v[to[i]];
if(i&1)ans[id[i]]=v[to[i]];else ans[id[i]]=-v[to[i]];
}
}
int main()
{
freopen("flow.in","r",stdin);
freopen("flow.out","w",stdout);
read(n);
for(int i=1;i<=n;i++)
read(a[i]),f[i]=i,s=s+a[i];
if(s)
{
puts("Impossible");
return 0;
}
puts("Possible");
read(m);tot=0;
for(int i=1;i<=m;i++)
{
read(x);read(y);
if(get(x)^get(y))
{
ins(x,y,i);
ins(y,x,i);
f[get(x)]=get(y);
}
}
dfs(1,0);
for(int i=1;i<=m;i++)
{
if(ans[i]<0)P('-'),ans[i]=-ans[i];
write(ans[i]);P('\n');
}
return 0;
}