LiberOJ #6210. 「美团 CodeM 决赛」tree 树形DP

题目链接:点这里

题解:

  需要证明,所求的路径一定是全部权值都为1或者,路径上权值至多有一个为2其余为1且权值2在路径中央。

  然后树形DP

  设定dp[i][0/1] 以1为根的情况下,以i 节点下子树走分别全1和 走一次2和剩余全走1 的最长链

  每遍历一次子树,统计一次答案

  下面给出代码

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 5e5+10, M = 1e3+20,inf = 2e9;
const LL mod = 1e9+7LL;

int n,a[N],ans;
int ans1,ans2;
vector<int > G[N];
int dp[N][2];
void dfs(int u,int f) {
    if(a[u] == 1) dp[u][0] = 1;
    else if(a[u] == 2) dp[u][1] = 1;
    for(int i = 0; i < G[u].size(); ++i) {
        int to = G[u][i];
        if(to == f) continue;
        dfs(to,u);
        ans1 = max(ans1,dp[to][0] + dp[u][0]);
        ans2 = max(ans2,dp[u][0] + dp[to][1]);
        ans2 = max(ans2,dp[u][1] + dp[to][0]);
        if(a[u] > 2)
            continue;

        if(a[u] == 1) {
            dp[u][0] = max(dp[u][0],dp[to][0] + 1);
            dp[u][1] = max(dp[u][1],dp[to][1] + 1);
        }
        else {
            dp[u][1] = max(dp[u][1],dp[to][0] + 1);
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i = 1; i < n; ++i) {
        int x,y;
        scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    int mi = inf;
    for(int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
        mi = min(mi,a[i]);
    }
    ans = 0;
    dfs(1,0);
    if(mi >= 2) {
        printf("%d/1\n",mi);
    }
    else {
        if(2*ans1 > ans2) printf("1/%d\n",ans1);
        else if(ans2 % 2 == 0) printf("1/%d\n",ans2/2);
        else printf("2/%d\n",ans2);
    }
    return 0;
}
时间: 2024-10-18 15:41:09

LiberOJ #6210. 「美团 CodeM 决赛」tree 树形DP的相关文章

LibreOJ #6191. 「美团 CodeM 复赛」配对游戏

二次联通门 : LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 /* LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 概率dp 不是很懂为什么这样做... */ #include <cstdio> #include <iostream> const int BUF = 12312312; char Buf[BUF], *buf = Buf; inline void read (int &now) { for (now = 0; !isdi

「题解」「美团 CodeM 资格赛」跳格子

目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞定,最后无奈 \(90pts\) . 然而 \(T2\) 想到很多很奇怪的做法,结果正解在 \(28min\) 之内做出... 结果 \(T3\) 是本人最不擅长的伪期望,直接跳过,啥都没得. 来水一发 \(T1\) 的题解... 题目描述 点这里 考场思路 其实并没有什么十分特别的思路,就是一通乱

「美团 CodeM 资格赛」试题泛做

LibreOJ真是吼啊! 数码 推个式子,把枚举因数转为枚举倍数.然后就发现它是根号分段的.然后每一段算一下就好了. 1 #include <cstdio> 2 #include <cstring> 3 4 #define R register 5 typedef long long ll; 6 struct Data { 7 ll num[10]; 8 inline void clear() 9 { 10 memset(num, 0, 10 << 3); 11 } 1

「美团 CodeM 复赛」城市网络

https://loj.ac/problem/6192 内存限制:64 MiB   时间限制:500 ms标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接的连通图),首都为 111 号城市,每个城市售卖价值为 aia_ia?i?? 的珠宝. 你是一个珠宝商,现在安排有 qqq 次行程,每次行程为从 uuu 号城市前往 vvv 号城市(走最短路径),保证 vvv 在 uuu 前往首都的最短路径上. 在每次行程开始时,你手上有价值为 ccc 的珠宝(

#6085. 「美团 CodeM 资格赛」优惠券

题目描述 用last[x]表示对x进行的上一次操作的位置,vis[x]表示x是否在大楼内. Splay维护'?'的位置. 若x要进楼: 1.若x已在楼内,则去找last[x]到i之间是否有'?',若有,则可以把这个'?'当做是上一个x出楼,反之则 出现错误. 2.若x不在楼内,标记x在楼内. 若x要出楼: 1.若x在楼内,标记x不在楼内. 2.若x不在楼内,相同的去找last[x]到i之间是否有'?'. #include<complex> #include<cstdio> usin

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m

codeforces161D - Distance in Tree 树形dp

题意:给你一棵树,问你树中距离为k的有多少种情况. 解题思路:树形dp  维护每个节点(1-K)深度的情况, 解题代码: 1 // File Name: 161d.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月03日 星期日 19时20分10秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #incl

hdu5593/ZYB&#39;s Tree 树形dp

ZYB's Tree Memory Limit: 131072/131072 K (Java/Others) 问题描述 ZYBZYB有一颗NN个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,BA,B,令fa_ifa?i??为节点ii的父亲,fa_1=0fa?1??=0;fa_i=(A*i+B)\%(i-1)+1fa

URAL_1018 Binary Apple Tree 树形DP+背包

这个题目给定一棵树,以及树的每个树枝的苹果数量,要求在保留K个树枝的情况下最多能保留多少个苹果 一看就觉得是个树形DP,然后想出 dp[i][j]来表示第i个节点保留j个树枝的最大苹果数,但是在树形过程中,有点难表示转移 后来看了下大神的做法才知道其实可以用背包来模拟 树枝的去留,其实真的是个背包诶,每个子树枝就相当于物品,他占用了多少树枝量,带来多少的收益,就是用背包嘛,于是用树形DP+背包就可以做了 #include <iostream> #include <cstdio> #