• CF901D Weighting a Tree


    一、题目

    点此看题

    二、解法

    从问题的简单情形开始考虑,如果无向图是一棵树怎么办?我们可以从叶子往上构造,要让叶子合法边的权值只有一种可能,所以最后我们能让除了根的所有点都一定合法。

    那么扩展到图上,我们可以找出原图的一棵 \(\tt dfs\) 树,然后把非树边的边权赋值成 \(0\),按树的方法做就只有根的问题需要解决了。然后我们使用调整法,也就是调整非树边的边权让根也合法。

    调整多条边是很困难的事,所以现在我们就开始找结论吧,首先考虑让答案合法的必要条件是现在的权值是偶数。然后我们着重从非树边构成环的奇偶性来考虑,考虑偶环是没有用的,因为它不能把修改的点权集中在一个点上,所以调整偶环是没有作用的,我们忽略它。

    再考虑调整奇环,如果非树边设置的权值是 \(x\),首先我们要让换上的点合法,那么环根的点权会变化 \(2x/-2x\),我们再把这个影响传递到根上面,那么调整后根会相应的变化 \(2x/-2x\)(取决于根到环的距离),这说明只要存在奇环就是有解的,调整只需要用到这条非树边。

    最后说一下实现的细节,我们可以把奇环的环根当成树根建树,这样调整起来会方便一些。

    三、总结

    很多变元的构造题中,可以只考虑少部分的变元就能给出构造方案。

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int M = 100005;
    #define int long long 
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,rt,nw,id,a[M],b[M],dep[M],fa[M],pr[M],pid[M];
    struct node {int v,id;};vector<node> g[M];
    void dfs1(int u,int p)
    {
    	dep[u]=dep[fa[u]=p]+1;
    	for(auto x:g[u]) if(p!=x.v)
    	{
    		if(!nw && dep[x.v] && (dep[u]-dep[x.v])%2==0)
    		{
    			rt=u;nw=x.v;id=x.id;
    			for(int i=u;i!=x.v;i=fa[i]) pr[i]=fa[i];
    		}
    		if(!dep[x.v]) dfs1(x.v,u);
    	}
    }
    void dfs2(int u,int p)
    {
    	dep[u]=dep[fa[u]=p]+1;
    	for(int t=0;t<2;t++) for(auto x:g[u])
    		if((t || x.v==pr[u]) && !dep[x.v] && x.id!=id)
    			pid[x.v]=x.id,dfs2(x.v,u);
    	a[fa[u]]-=(b[pid[u]]=a[u]);
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<=m;i++)
    	{
    		int u=read(),v=read();
    		g[u].push_back(node{v,i});
    		g[v].push_back(node{u,i});
    	}
    	rt=1;dfs1(1,0);
    	memset(dep,0,sizeof dep);
    	dfs2(rt,0);
    	if(nw)
    	{
    		int d=a[rt]/2;a[rt]%=2;b[id]+=d;
    		for(int fl=-d;nw!=rt;fl=-fl)
    			b[pid[nw]]+=fl,nw=fa[nw];
    	}
    	if(a[rt]) {puts("NO");return 0;}
    	puts("YES");
    	for(int i=1;i<=m;i++) printf("%lld\n",b[i]);
    }
    
  • 相关阅读:
    react 把时间戳用new Date改为日期
    react-格式化日期
    react-2种方法写法
    React-router4简约教程
    react-addons-css-transition-group
    vue-一些易错点
    Js apply方法详解,及其apply()方法的妙用
    C++中的继承(3)作用域与重定义,赋值兼容规则
    C++中的继承(1) 继承方式
    vim中文帮助文档安装
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15811525.html
Copyright © 2020-2023  润新知