zoukankan      html  css  js  c++  java
  • 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;
    }
    
    转载需注明出处。
  • 相关阅读:
    LeetCode100-相同的树
    LeetCode66-加一
    LeetCode102-二叉树的层序遍历
    dubbo协议端口
    http错误-413 Request Entity Too Large
    【Jeecg Vue】通过getAction的finally来最大程度避免影响主数据呈现
    图片压缩,用这个就够了
    信息数据安全,日常办公你就要注意这些!
    java笔记:流式编程 数组与List集合互转
    改状态,你会改吗?你真的会改吗?
  • 原文地址:https://www.cnblogs.com/jz929/p/11817520.html
Copyright © 2011-2022 走看看