题目链接:CF 或者 洛谷

首先基于一个事实,答案一定是生成树,显然,每次我们都需要连边,每次都会 \(-x\),那么一共会减少 \((n-1)\times x\),很显然的一个必要条件为:

\[\sum_{i=1}^{n}a_i \ge (n-1) \times x \ 显然一定成立。
\]

现在我们用来证明它同时也是一个充分条件,不妨设:

\[a_1 \le a_2 \le a_3\le a_4.... \le a_n,且\ \sum_{i=1}^{n}a_i \ge (n-1) \times x。
\]

假如无法找到 \(a_i+a_j \ge x\),不妨考虑极端情况,考虑与 \(a_n\) 相连的点 \(a_i\),假如有 \(a_i+a_n < x\),显然有 \(a_n<x-a_i\),所以此时有:

\[a_1 \le a_2 \le a_3...a_n < x-a_i,\sum_{i=1}^{n}a_i <(n-1)\times (x-a_i)+a_i
\]
\[\Rightarrow 原式<(n-1)\times x-(n-2)\times a_i,又知道\ n \ge 2,显然与条件矛盾。
\]

反证出我们一定能找到一组 \(a_i+a_j \ge x\)。我们将它取出,点数 \(-1\),总权减少了 \(x\):

\[\sum_{i=1}^{n-1}a_i \ge (n-2) \times x,显然又是一个同样的子问题。
\]

而 \(i=2\) 时,显然成立,所以这不仅是一个必要条件,同时还是个充分条件。

考虑构造的强结论

基于上述我们知道的充要条件,即满足那个式子以后,我们每次取出一对满足题意的点对,一定能构造出答案,现在我们来考虑不满足的情况,显然全部都 \(a_i \ge x\) 一定可以随意构造出答案,我们考虑不满足时有:

\[a_1 \le a_2 \le a_3....<x \le a_i \le a_{i+1}...\le a_n
\]

这个式子一定是成立的,否则找不到当前一对不满足题意的点,我们可以画出它的连边可能性图:

很显然,有三类可能性边:

  1. \(a_i,a_j \ge x\),这类显然满足题意。

  2. $a_i \ge x,a_j <x $,这类也显然满足题意。

  3. \(a_i,a_j <x\),这类可能和 \(\ge x\),也可能 \(<x\)。

我们其实只需要考虑 \(<x\) 的这种该如何通过其他边激活成功。我们考虑其他三类边对它的影响,很显而易见需要考虑的是如图中的 \(1-2\) 这条边。而激活一条边,把另一个点的点权减去 \(x\) 即 \(a_i-x\) 加到自身可能会使得变大变小,因为 \(a_i<x\) 或者 \(a_i>x\) 都有可能能激活边。

在讨论之前,我们需要明确一点,那就是答案是一棵生成树,当然 \(dfs 树\) 也行,考虑任意一棵都满足吗?答案是肯定的,基于充要条件,我们任意一棵树都可以至少找到一组点对,使得不断缩小为更小问题,那么很显然,我们从任意一棵生成树来讨论这三类边的影响:

如图所示,红色表示已经满足题意的可行边,蓝色表示不可行边(显然不可行边两个端点点权一定都 \(<x\)),当红色边激活后会使得某些蓝色边转化为红色边,然后再次重新激活红色边(当然也有可能某些红色边激活使得其他红色边变为了蓝色边),依次的进行激活所有边。

我们来考虑一个有意思的东西:

很显然叶子节点当除自身以外的所有边都激活时,一定会和剩下的连通块激活。举个例子,比如 \(6-3\) 这条蓝色边,当 \(3\) 与其他所有边除了 \(3-6\) 以外都变成红色了,那么 \(3-6\) 这条蓝色边一定可以变成红色边,基于充要条件。

加强结论:

对于例如 \(3\) 连接的所有叶子节点来说,当除了这些连边以外,与 \(3\) 连接的其他边变成红色以外,例如本图中即为 \(1-3\) 染成了红色以后,剩余的叶子节点边都能 “不计顺序” 地染成红色。

考虑反证法证明:

基于上述的三类边,显然当染色成红色边以后可大可小,大的情况为另一个和他染色的节点为 \(>x\),否则为 \(<x\)。而此时除了叶子节点以外对 \(3\) 已无影响,并且此时此刻的所有需要判断的叶子节点只有 “原本为” 蓝色边叶子节点,红色边我们已经能激活的全部激活了,所以这意味着这些剩余的叶子节点一定都是 \(<x\) 的,即对这个父节点影响是 “减小”,并不存在增大。

我们考虑依次操作叶子节点的影响,假如反复使得它变小,一直到某个叶子结点 \(a_i+a_3\) 无法染成红色,那显然这等价于无解,显然这个是不可能的,基于上述说的充要条件一定有解。所以叶子节点无论顺序,一定都能被染成红色边。

考虑子问题,把所有叶子节点放在最后一次染色,这等价于生成树少了一层,而其他情况就是正儿八经地能连就连,这样一来原图少一层就变为了:

这其实是一模一样的子问题(当然可能有蓝色边变为了红色边,而红色边变为了蓝色边,因为可大可小)。所以我们得到了最终的策略,从下往上贪心,每一层的叶子节点放在最后进行激活,能够激活的点优先激活,这样一来任意一棵 \(DFS\) 树我们都能正确地构造出答案了。

参照代码
#include <bits/stdc++.h>

// #pragma GCC optimize("Ofast,unroll-loops")
// #pragma GCC optimize(2) // #define isPbdsFile #ifdef isPbdsFile #include <bits/extc++.h> #else #include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope> #endif using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; template <typename T>
int disc(T* a, int n)
{
return unique(a + 1, a + n + 1) - (a + 1);
} template <typename T>
T lowBit(T x)
{
return x & -x;
} template <typename T>
T Rand(T l, T r)
{
static mt19937 Rand(time(nullptr));
uniform_int_distribution<T> dis(l, r);
return dis(Rand);
} template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
return (a % b + b) % b;
} template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
a %= c;
T1 ans = 1;
for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
return modt(ans, c);
} template <typename T>
void read(T& x)
{
x = 0;
T sign = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')sign = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
x *= sign;
} template <typename T, typename... U>
void read(T& x, U&... y)
{
read(x);
read(y...);
} template <typename T>
void write(T x)
{
if (typeid(x) == typeid(char))return;
if (x < 0)x = -x, putchar('-');
if (x > 9)write(x / 10);
putchar(x % 10 ^ 48);
} template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
write(x), putchar(c);
write(c, y...);
} template <typename T11, typename T22, typename T33>
struct T3
{
T11 one;
T22 tow;
T33 three; bool operator<(const T3 other) const
{
if (one == other.one)
{
if (tow == other.tow)return three < other.three;
return tow < other.tow;
}
return one < other.one;
} T3() { one = tow = three = 0; } T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
{
}
}; template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
if (x < y)x = y;
} template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
if (x > y)x = y;
} constexpr int N = 3e5 + 10;
ll sumA;
ll a[N];
int n, m;
int front, last; //前面放可以先激活的边,后面放下层的叶子节点连边
int ans[N];
vector<pii> child[N];
ll x;
bool vis[N]; inline void dfs(const int curr)
{
vis[curr] = true;
for (const auto [nxt,id] : child[curr])
{
if (vis[nxt])continue;
dfs(nxt);
if (a[curr] + a[nxt] >= x)a[curr] += a[nxt] - x, ans[front++] = id;
else ans[last--] = id;
}
} inline void solve()
{
cin >> n >> m >> x;
forn(i, 1, n)cin >> a[i], sumA += a[i];
forn(i, 1, m)
{
int u, v;
cin >> u >> v;
child[u].emplace_back(v, i);
child[v].emplace_back(u, i);
}
if (sumA < (n - 1) * x)
no << endl;
else
{
yes << endl;
front = 1, last = n - 1;
dfs(1);
forn(i, 1, n-1)cout << ans[i] << endl;
}
} signed int main()
{
// MyFile
Spider
//------------------------------------------------------
// clock_t start = clock();
int test = 1;
// read(test);
// cin >> test;
forn(i, 1, test)solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
// clock_t end = clock();
// cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}
\[时间复杂度为:\ O(n+m)
\]

CF1515F Phoenix and Earthquake 题解的更多相关文章

  1. [CF1515F] Phoenix and Earthquake(图论推导,构造)

    题面 在紧张又忙碌地准备联合省选时,发生了大地震,把原本要参赛的 n n n 个城市之间的全部 m m m 条道路震垮了,使得原本互相都能到达的这 n n n 个城市无法交通了.现在,需要紧急恢复 n ...

  2. 题解 CF1348D 【Phoenix and Science】

    题目大意,每天细菌会在早上选择分裂,晚上生长. 观察题目,我们可以发现.不管我们怎么分裂细菌,这一天晚上的总质量都是前一天晚上的总质量加上今天的细菌数. 那么我们肯定希望细菌分裂的越多越好,这样我们减 ...

  3. bzoj usaco 金组水题题解(2)

    续.....TAT这回不到50题编辑器就崩了.. 这里塞40道吧= = bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害 比较经典的最小割?..然而 ...

  4. bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害

    1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害 Description Farmer John的农场里有P个牧场,有C条无向道路连接着他们,第i条道路连接着 ...

  5. Phoenix综述(史上最全Phoenix中文文档)

    个人主页:http://www.linbingdong.com 简书地址:http://www.jianshu.com/users/6cb45a00b49c/latest_articles 网上关于P ...

  6. 在DBeaver中phoenix查询报错:org.apache.phoenix.exception.PhoenixIOException: The system cannot find the path specified

    环境:Phoenix:4.4,win7系统 问题:Phoenix在查询hbase时,报"系统找不到指定路径". 解决: 请参见 https://distcp.quora.com/C ...

  7. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  8. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  9. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  10. HBase+Phoenix整合入门--集群搭建

    环境:CentOS 6.6 64位    hbase 1.1.15  phoenix-4.7.0-HBase-1.1 一.前置环境: 已经安装配置好Hadoop 2.6和jdk 1.7 二.安装hba ...

随机推荐

  1. 五分钟,手撸一个简单的Spring容器

    工厂和Spring容器Spring是一个成熟的框架,为了满足扩展性.实现各种功能,所以它的实现如同枝节交错的大树一样,现在让我们把视线从Spring本身移开,来看看一个萌芽版的Spring容器怎么实现 ...

  2. vue 状态管理 一、状态管理概念和基本结构

    系列导航 vue 状态管理 一.状态管理概念和基本结构 vue 状态管理 二.状态管理的基本使用 vue 状态管理 三.Mutations和Getters用法 vue 状态管理 四.Action用法 ...

  3. [Violation] Added non-passive event listener to a scroll-blocking 'mousewheel' event.

    在基于 Element-ui 写项目的时候,Chrome 提醒: [Violation] Added non-passive event listener to a scroll-blocking ' ...

  4. 《模拟龙生》|500行Go代码写一个随机冒险游戏|巨龙修为挑战开启

    一.前言 新年就要到了,祝大家新的一年: 龙行龘龘, 前程朤朤! 白泽花了点时间,用 500行 Go 代码写了一个控制台的小游戏:<模拟龙生>,在游戏中你将模拟一条新生的巨龙,开始无尽的冒 ...

  5. java基础-idea的使用-day07

    目录 1. idea的获取 2. 已经安装的idea 如何卸载 3. idea的安装与破解 3. 设置 4. 写代码常用快捷建的使用 1. idea的获取 链接:https://pan.baidu.c ...

  6. KVM 核心功能:CPU 虚拟化

    1 vCPU 简介 CPU 负责计算机程序指令的执行.QEMU-KVM 提供对虚拟机 CPU 的模拟,对于虚拟机来说,其拥有的 CPU 是真实的, 和物理 CPU 没有区别. 实际上,虚拟机在 hos ...

  7. docker 安装 nacos

    转载请注明出处: https://www.jianshu.com/p/54f6da71ac48

  8. Cortex-M3 MCU的技术特点

    1.Cortex-M3 MCU的技术特点 MCU简单来说就是一个可编程的中央处理器(CPU)加上一些必要的外设.不管是中央处理器还是整个MCU都是复杂的时序数字电路,根据程序或者指令来完成特定的任务. ...

  9. 274. H 指数

    1.题目介绍 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数.计算并返回该研究者的 h 指数. 根据维基百科上 h 指数的定义:h 代表 ...

  10. Redis在Liunx系统下使用

    Redis使用 前言 如何在Linux服务器上部署Redis,版本号如下: Redis版本 5.0.4 服务器版本 Linux CentOS 7.6 64位 下载Redis 进入官网找到下载地址 ht ...