AT2304 Cleaning

title

LUOGU AT2304

简化题意:

一棵树,第 \(i\) 个节点上有 \(a_i\) 个石头,每次选择两个叶子节点(度数为 1 的节点),将路径上经过的(包括起点终点)所有节点上都取走一个石头,如果路径上有一个点上没石头这个操作就不能进行,问能不能取完所有石头。

analysis

取一非叶节点作为树的根。设节点 \(x\) 的点权为 \(A[x]\) (根据题意,这个点权可以理解为经过节点 \(x\) 的路径总数) 。

对任意非叶节点 \(x\) ,设 \(x\) 的儿子 \(y\)\(A[y]\) 之和为 \(sum\) ,设 \(a\) 为经过 \(x\) 且在 其子树 中的路径数,\(b\) 为经过 \(x\) 且不在 其子树 中的路径数,则有方程组
\[ \begin{cases}2*a+b=sum\\ a+b=A[x]\end{cases} \]

所以
\[ \begin{cases}a=sum-A[x]\\ b=2*A[x]-sum\end{cases} \]

再进行一些必要性的检验,如
\[ a\geqslant 0、b\geqslant 0、a\leqslant\min\left\{sum-maxpart,sum/2\right\}(maxpart~为~x~的儿子~y~的~A[y]~的最大值) \]

\(x\) 为根则 \(b=0\)

最后令 \(A[x]=b\)

以上就是 \(dfs\) 的构思过程。

还要特判一下 \(n=2\) 的情况(因为无法确定根):如果两个节点点权相同则合法。

结合起来就可以解决这道题目了。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

int ver[maxn<<1],Next[maxn<<1],head[maxn],len,deg[maxn];
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

ll A[maxn];
bool flag=1;
inline void dfs(int x,int fa)
{
    ll sum=0,maxpart=0; int o=0;
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==fa) continue;
        ++o;
        dfs(y,x);
        sum+=A[y];
        maxpart=max(maxpart,A[y]);
    }
    if (!o) return ;
    ll a=sum-A[x],b=(A[x]<<1)-sum;
    if (a<0 || b<0 || a>min(sum-maxpart,sum>>1) || (fa==-1 && b)) flag=0;
    A[x]=b;
}

int main()
{
    int n;read(n);
    for (int i=1; i<=n; ++i) read(A[i]);
    for (int i=1,a,b; i<n; ++i) read(a),read(b),add(a,b),add(b,a),++deg[a],++deg[b];
    int root=0;
    for (int i=1; i<=n; ++i)
        if (deg[i]>1) { root=i; break; }
    if (root) dfs(root,-1);
    else flag=(A[1]==A[2]);
    puts(flag?"YES":"NO");
    return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/11353272.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值