Decay of Signals【2020 年 “遊族杯” D題】【樹形dp】

題目鏈接


  這題有一個規律的東西,就是我們實際上只需要看1、2的鏈,譬如說有一個大於2權值爲k的點,如果它的周圍有權值爲1的點的話,那麼我們實際上沒有必要去選上k,只需要選1即可,因爲若是選上權值爲k的話,k > 2,那麼需要使得要取的值爲1的點的個數爲x的情況下:\frac{k}{k * x + 1} < \frac{1}{x},又有k > 2,所以必須存在一條存在點度大於2的鏈,顯然,這是不現實的,所以我們只需要考慮1、2兩個點就是了,0的時候答案自然爲“0/1”,若是沒有1、2和0那肯定就是每個點“minn/1”就是了。

  所以,關於2,還是要特殊的,\frac{2}{2 * x + 1} < \frac{1}{x}需要保證的是,2的兩邊的x數量是對等的,若是有一邊偏大,那麼直接選那一邊不是更好嗎?

  然後我們維護這個式子\frac{2}{2 * x + 1},去找最大的滿足條件的x。所以,這裏可以向上遞推的來解決。

  我們還需要維護一個dp[u]表示u這個點向下只走“1”的最遠能到達的距離。

10
1 2
1 3
1 4
2 5
2 6
3 7
6 8
8 9
7 10
1 3 3 2 1 1 1 3 1 2
ans:1/1
5
1 2
2 3
3 4
4 5
1 1 2 1 1
ans:2/5
3
1 2
1 3
2 1 1
ans:2/3
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
struct pir
{
    int fir, sec;
    pir(int a=0, int b=0):fir(a), sec(b) {}
    friend bool operator < (pir e1, pir e2) { return e1.fir == e2.fir ? e1.sec > e2.sec : e1.fir > e2.fir; }
    friend bool operator == (pir e1, pir e2) { return e1.fir == e2.fir; }
};
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
const int maxN = 1e6 + 7;
int N, head[maxN], cnt;
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
} edge[maxN << 1];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
int a[maxN], ans[2], deep[maxN], dp[maxN];
pir vt[maxN];
void Min(int *x, int y[2])
{
    if(1LL * x[0] * y[1] > 1LL * x[1] * y[0]) { x[0] = y[0]; x[1] = y[1]; }
}
void dfs(int u, int fa)
{
    int tmp[2];
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        deep[v] = (a[v] == 1 ? deep[u] + 1 : 0);
        dfs(v, u);
        if(a[u] == 1)
        {
            tmp[0] = 1; tmp[1] = dp[u] + 1 + dp[v];
            Min(ans, tmp);
            if(vt[v] < vt[u])
            {
                vt[u] = vt[v];
                if(vt[u].sec + 1 + dp[u] == vt[u].fir)
                {
                    tmp[0] = 2; tmp[1] = 1 + 2 * vt[u].fir;
                    Min(ans, tmp);
                }
            }
            else
            {
                if(vt[u].sec + 1 + dp[v] == vt[u].fir)
                {
                    tmp[0] = 2; tmp[1] = 1 + 2 * vt[u].fir;
                    Min(ans, tmp);
                }
            }
        }
        else if(a[u] == 2)
        {
            tmp[0] = 2; tmp[1] = 2 * min(dp[u], dp[v]) + 1;
            Min(ans, tmp);
        }
        dp[u] = max(dp[u], dp[v]);
    }
    if(a[u] == 1)
    {
        dp[u] ++;
        vt[u].sec ++;
    }
    else if(a[u] == 2)
    {
        if(deep[fa] >= dp[u])
        {
            tmp[0] = 2; tmp[1] = 2 * dp[u] + 1;
            Min(ans, tmp);
        }
        else vt[u] = pir(dp[u], 0);
        dp[u] = 0;
    }
    else { dp[u] = 0; vt[u] = pir(INF, 0); }
    tmp[0] = 1; tmp[1] = dp[u];
    Min(ans, tmp);
}
inline void init()
{
    cnt = 0; ans[0] = INF; ans[1] = 1;
    for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
    scanf("%d", &N);
    init();
    for(int i=1, u, v; i<N; i++)
    {
        scanf("%d%d", &u, &v);
        _add(u, v);
    }
    for(int i=1; i<=N; i++)
    {
        int tmp[2];
        scanf("%d", &a[i]);
        tmp[0] = a[i]; tmp[1] = 1;
        Min(ans, tmp);
    }
    deep[1] = (a[1] == 1 ? 1 : 0);
    dfs(1, 0);
    int _GCD = gcd(ans[0], ans[1]);
    printf("%d/%d\n", ans[0] / _GCD, ans[1] / _GCD);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章