首页 > 其他分享 >CF1515F Phoenix and Earthquake 题解

CF1515F Phoenix and Earthquake 题解

时间:2024-01-26 12:22:06浏览次数:22  
标签:typedef CF1515F 题解 int ge template include Earthquake define

题目链接: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 树\) 也行,考虑任意一棵都满足吗?答案是肯定的,基于充要条件,我们任意一棵树都可以至少找到一组点对,使得不断缩小为更小问题,那么很显然,我们从任意一棵生成树来讨论这三类边的影响:

如图所示,红色表示已经满足题意的可行边,蓝色表示不可行边,当红色边激活后会使得某些蓝色边转化为红色边,然后再次重新激活红色边,依次的进行激活所有边。

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

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

加强结论:

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

考虑反证法证明:

基于上述的三类边,显然当染色成红色边以后可大可小,大的情况为另一个和他染色的节点为 \(>x\),否则为 \(<x\)。而此时除了叶子节点以外对 \(3\) 已无影响,我们考虑依次操作叶子节点的影响,假如反复使得它变小,一直到某个叶子结点 \(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) \]

标签:typedef,CF1515F,题解,int,ge,template,include,Earthquake,define
From: https://www.cnblogs.com/Athanasy/p/17989073

相关文章

  • latex常见问题解决
    1.Fileendedwhilescanninguseof\@writefile解决方法:删除编译文件夹内.aux扩展名结尾的文件,重新用Latex命令进行编译,自动生成正确的aux文件,完成错误的修复。注:如果还不好使,就把除.tex以外的文件均删除掉,如:.bbl,.blg,.dvi,.log等2.多行缩进ctrl+a全选后,shift+tab向前退......
  • [Bzoj 3252] 攻略 题解
    攻略题面\(n(\le2\cdot10^5)\)个点的有根树,\(k(\len)\)次从根走到叶子,每个点有权值,求经过的点的权值和的最大值.(同一个点只能算一次)Sol1我们设想一个叶子一个叶子加进去的过程。如果有两个从某个点到叶子的路径,我们可以如图把他分成两条路径。那么他满足贪心,也就是每次......
  • P4159 [SCOI2009] 迷路 题解
    P4159[SCOI2009]迷路搬运工题目链接首先我们先考虑这道题的弱化版如何处理。假如所有的边权都是零和一。这时他们的边权可以看做这两个点走一步到达之间的方案数。而对于走t步,我们可以推出下列式子,\(f_{i,j}\)表示从节点\(i\)到节点\(j\)的方案数。\[f_{i,j}=\su......
  • # python3 安装Crypto包 出现No module named ‘Crypto‘和No module named ‘Crypto.
    python3安装Crypto包出现Nomodulenamed‘Crypto‘和Nomodulenamed‘Crypto.Util‘问题解决方法1.改成安装pycryptodome然而在python36中无法报错:error:MicrosoftVisualC++14.0orgreaterisrequired"2.改用Anaconda安装指定版本的pycryptodomepipins......
  • 2024年1月Java项目开发指南12:前后端分离项目跨域问题解决
    创建config文件夹,创建WebConfig文件代码如下(可以直接抄)packagecc.xrilang.serversystem.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.se......
  • CF145E Lucky Queries 题解
    题目链接:CF或者洛谷前置知识点:序列操作本文关键词约定俗称:因为频繁敲最长不下降子序列\(LNCS\)和最长不上升子序列\(LNIS\)太麻烦了,下文将\(000011111\)这种最长不降子序列用\(LIS\)描述,\(1111100000\)这种最长不升子序列用\(LDS\)描述。这里面只有\(4\)和\(7......
  • 魔法少女LJJ 题解
    魔法少女LJJ题解这题纯属就是迷惑题。。为什么这么说?注意数据范围:对100%的数据\(0\leqm\leq400000\),\(c\leq7\)。\(c\leq7\)!!这意味着根本没有删除操作。就连样例也是错的。Solution这题的各种操作,用并查集+线段树合并完成。如果你是被题目数据范围晃飞的,建议......
  • loj 6095 花神的嘲讽计划 题解
    题目哈希记录每个\(k\)长度的串,询问的时候可以拿主席树或二分,这里说下二分。将\(n-k+1\)个串从小到大排序,以哈希值为第一关键字,序号为第二关键字。每次询问直接查找大于等于当前哈希值的位置即可,找到之后判断一下合不合法即可。具体看代码:#include<bits/stdc++.h>typede......
  • P8659 [蓝桥杯 2017 国 A] 数组操作 题解
    题目链接:洛谷或者蓝桥杯或者C语言中文网几个OJ的AC记录:忘了哪个OJ的:洛谷:C语言中文网:蓝桥杯:emmmmmmm,好像每个OJ给的时限和空间还不一样,蓝桥杯官方还给了$3s$和$2G$,C语言中文网机子比较老可能,挺卡常的,开了个究极快读和指令集就过去了,也可以自己调下重构常数,偷懒......
  • P3355 骑士共存问题题解
    题目链接:P3355骑士共存问题-洛谷|计算机科学教育新生态(luogu.com.cn)题解:棋盘问题考虑黑白染色成为二分图后做。观察马的性质,可知一个点只能到一个异色点,所以,构造方案可以先将所有同色点放上马,再考虑有那些异色点不可以放置。方法一:网络流,时间复杂度为O(|E|min(|E|0.5......