jzoj 3317. 【BOI2013】管道

Question

给你nn个点mm条边,点之间相互连通。每个点的值等于其所连的边的值的一半的和,告诉你每个点的值。
对于边的值:如果有唯一解,则输出唯一解,否则输出00

Solution

对于这道题,我们来看一看nnmm的关系。
n1==mn-1==m
我们可以发现,这是一棵树,且有些节点只连了一条边,很容易求出边权,并将其所连的点进行更改即可删掉此边,不断如此即可。
n<mn<m
线性方程组的方程数小于变量数,不可能有唯一解。
n==mn==m
我们发现会有一个环。
对于这个环以外的值,我们像n1==mn-1==m那样做,最后只剩下一个环。
如果这个环有偶数个点的话,没有唯一解,输出00。(鄙人太弱,不会证明)
如果有奇数个点的话,一定有唯一解。
对于奇数个点(设有NN个点),我们可以将其列出NN个方程,
自己想一想,解一解即可。

Code

#include<cstdio>
#include<cstring>
#define N 100010
#define ll long long
using namespace std;
struct node{int v,fr,sg;}e[N<<1];
int n,m,tail[N],hav[N],rem[N],edge[N],cnt=0;
int f[N],l=0,r=0,las,ha=0;
ll c[N],aw[N],s=0,ss=0;
bool bz[N],bz1[N];

inline int read()
{
	int x=0,f=0; char c=getchar();
	while (c<'0' || c>'9') f=(c=='-') ? 1:f,c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return f ? -x:x;
}

inline void add(int u,int v,int sg) {e[++cnt]=(node){v,tail[u],sg}; tail[u]=cnt;}

int main()
{
	freopen("tube.in","r",stdin);
	freopen("tube.out","w",stdout);
	n=read(),m=read();
	if (m>n) {puts("0"); return 0;}
	for (int i=1;i<=n;i++) c[i]=read();
	for (int i=1,u,v;i<=m;i++)
	{
		u=read(),v=read();
		add(u,v,i),add(v,u,i);
		hav[u]++,hav[v]++;
	}
	for (int i=1;i<=n;i++)
		if (hav[i]==1) f[++r]=i;
	while (l++<r)
	{
		for (int p=tail[f[l]],v,sg;p;p=e[p].fr)
		{
			sg=e[p].sg;
			if (!bz[sg]) aw[sg]=c[f[l]]<<1,bz[sg]=1;
			v=e[p].v,hav[v]--,c[v]-=c[f[l]];
			if (hav[v]==1) f[++r]=v;
		}
	}
	if (m==n-1) {for (int i=1;i<=m;i++) printf("%lld
",aw[i]); return 0;}
//	int haia=0;
//	for (int i=1;i<=n;i++)
//		if (hav[i]>1) haia++,printf("%d ",i);
//	printf("%d
",haia);
	for (int i=1;i<=n;i++)
		if (hav[i]>1) {rem[2]=i,ha=1; break;}
	for (int p=tail[rem[2]],v;p;p=e[p].fr)
	{
		v=e[p].v;
		if (hav[v]>1)
		{
			if (ha==1) rem[1]=v,edge[2]=e[p].sg,ha=3;
			else {rem[3]=v,edge[3]=e[p].sg; break;}
		}
	}
	l=1;memset(bz1,0,sizeof(bz1));
	bz1[rem[1]]=bz1[rem[2]]=bz1[rem[3]]=1;
	while (l++<ha)
	{
		for (int p=tail[rem[l]],v;p;p=e[p].fr)
		{
			v=e[p].v;
			if (hav[v]==1 || bz1[v]) continue;
			rem[++ha]=v,edge[ha]=e[p].sg,bz1[v]=1;
		}
	}
	for (int p=tail[rem[ha]];p;p=e[p].fr)
		if (e[p].v==rem[1]) edge[1]=e[p].sg;
	if (!(ha & 1)) {puts("0"); return 0;}
	for (int i=1;i<=ha;i++) ss+=c[rem[i]];
	for (int i=1;i<ha;i+=2) s+=c[rem[i]];
	aw[edge[ha]]=ss-(s<<1);
	for (int i=ha-1;i>0;i--)
		aw[edge[i]]=(c[rem[i]]<<1)-aw[edge[i+1]];
	for (int i=1;i<=m;i++)
		printf("%lld
",aw[i]);
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/11817520.html