CF1515F Phoenix and Earthquake

CF1515F Phoenix and Earthquake

证明题。

思路

考虑不合法的情况,如果 \(\sum a_i < (n-1)\times x\),肯定是不合法的。

再考虑对于一个可行的情况,最后缩的边肯定形成一棵树,所以我们大胆假设:任意一棵生成树只要满足 \(\sum a_i \geq (n-1)\times x\) 有合法的缩边方案。

考虑归纳证明:

\(n\) 个点的树中考虑叶子节点 \(u\),其父亲为 \(v\)

  1. \(a_u < x\),那么我们删除 \((u,v)\) 这条边,由于所需总和 \((n-1)\times x\) 减少了 \(x\),而 \(\sum a_i\) 减少了 \(a_u\),所以归纳假设任然成立。将边 \((u,v)\) 加入栈。

  2. \(a_u \geq x\),那么我们把 \(a_u\)\(a_v\) 进行缩点,原树转化为 \(n-1\) 个节点新树。将边 \((u,v)\) 加入队列。

先使用队列输出边,再输出栈中的边

再给出这样的输出边的方案的正确性证明:

首先使用条件 \(2\) 中的边进行缩点,假设缩剩下了 \(t\) 个点,第 \(i\) 个点的点权为 \(a_i\)

此时有 \(\sum a_i \geq (t-1)\times x\)

其中仅可能包括根节点的 \(a_i\) 大于 \(x\);否则,可以进一步进行 \(2\) 操作的缩点,将满足 \(a_i\geq x\)​ 的点缩到根节点处。

\(i>1\)\(a_i < x\),即 \(i>1\)\(x-a_i \geq 1\)

不妨设根节点的缩点点权为 \(a_1\),有 \(a_1 \geq \sum_{i=2}^t (x-a_i)\)

此时根节点可以与任意一个相连的缩点合并,不妨设该点为 \(t\)\(a_1\) 肯定大于等于 \(x-a_t\)),相当于不等式两边同时加了 \(a_t-x\),不等式仍然成立。

每次缩根节点和其相连的点就可以喽。

而我们根据栈输出的边正满足这样的条件,证明留给读者自行思考(doge)。

CODE

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define pii pair<int,int>
#define F first
#define S second

const int maxn=3e5+5;

int n,m,x;
ll a[maxn];

vector<pii>E[maxn];

bool vis[maxn];

queue<int>que;
stack<int>stk;

inline void dfs(int u)
{
    vis[u]=true;
    for(auto v:E[u])
    {
        if(vis[v.F]) continue;
        dfs(v.F);
        if(a[v.F]>=x) que.push(v.S),a[u]+=a[v.F]-x;
        else stk.push(v.S);
    }
}

int main()
{
    ll sum=0;
    scanf("%d%d%d",&n,&m,&x);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
    if(sum<1ll*(n-1)*x){printf("NO");return 0;}
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        E[u].push_back({v,i}),E[v].push_back({u,i});
    }
    dfs(1);
    puts("YES");
    while(!que.empty()) printf("%d\n",que.front()),que.pop();
    while(!stk.empty()) printf("%d\n",stk.top()),stk.pop();
}
posted @ 2024-05-21 19:29  彬彬冰激凌  阅读(3)  评论(0编辑  收藏  举报