ABC246G Game on Tree 3 题解

ABC246G Game on Tree 3 Solution

更好的阅读体验戳此进入

题面

类似于 LG-P3554 [POI2013]LUK-Triumphal arch,给定一棵树,有点权,B 初始在 $ 1 $,每轮 A 选择一个点将权值变为 $ 0 $,然后 B 移动一次,B 可在任意时刻停止游戏然后获得所在点上的权值的得分,两人均采取最优策略那么最终 B 最少会拿到多少的得分。

Solution

LG-P3554 [POI2013]LUK-Triumphal arch 基本相同,对于本题依然考虑二分答案,对于当前的答案 $ k $,认为树上点权大于 $ k $ 的贡献为 $ 1 $,小于等于的为 $ 0 $,于是显然可以树形 DP,令 $ dp(i) $ 表示 A 在 $ i $ 节点上时需要额外多少次的变为 $ 0 $ 的操作,显然有转移 $ dp(i) = \max(\sum_{j \in son(i)} dp(j) - 1, 0) + \left[ v(i) \gt k \right] $,最后判断一下根节点 $ 1 $ 为 $ 0 $ 则合法,反之不合法。

对于二分的当然可以直接二分值域,不过这里可以考虑一个小剪枝,上界显然为点权的最小值,若根节点有多个子树,那么下界显然为根节点连接的节点的点权的最小值。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template<typename T = int>
inline T read(void);

int N;
struct Edge{
    Edge* nxt;
    int to;
    OPNEW;
}ed[410000];
ROPNEW(ed);
Edge* head[210000];

int val[210000];
int mnval(INT_MAX), mxval(-1);
int f[210000];

void dfs(int k, int p = 1, int fa = 0){
    for(auto i = head[p]; i; i = i->nxt){
        if(SON == fa)continue;
        dfs(k, SON, p);
        f[p] += f[SON];
    }
    f[p] -= 1;
    f[p] = max(0, f[p]);
    f[p] += val[p] > k ? 1 : 0;
}
bool Check(int K){
    memset(f, 0, sizeof(f));
    dfs(K);
    return f[1] == 0;
}
int main(){
    N = read();
    for(int i = 2; i <= N; ++i)val[i] = read(), mxval = max(mxval, val[i]);
    for(int i = 1; i <= N - 1; ++i){
        int s = read(), t = read();
        head[s] = new Edge{head[s], t};
        head[t] = new Edge{head[t], s};
        if(s == 1)mnval = min(mnval, val[t]);
        if(t == 1)mnval = min(mnval, val[s]);
    }if(!head[1]->nxt)mnval = 0;
    int l = mnval, r = mxval;
    int ans(-1);
    while(l <= r){
        int mid = (l + r) >> 1;
        Check(mid) ? ans = mid, r = mid - 1 : l = mid + 1;
    }printf("%d\n", ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template<typename T>
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_10_21 初稿

posted @ 2022-10-24 08:10  Tsawke  阅读(22)  评论(0编辑  收藏  举报