1. 程式人生 > >APIO2010 巡邏

APIO2010 巡邏

ret pan clas hive www. include get str arc

為獲得更好的閱讀體驗請訪問我的 Blog

Luogu

每添加一條邊就會形成一個環,環上的邊就都只用經過一次。所以 \(k=1\) 時候求下樹的直徑,令直徑為 \(l_1\), \(2*(n-1)-l_1+1\) 就是答案了。

接下來我們來考慮 \(k=2\) 的時候。

肯定也是要連一條跟直徑類似的路徑的,但是可能會有邊與之前 \(k=1\) 時連的重復。這時候本來這條邊只需經過一次,現在變成了兩次。所以,要將 \(k=1\) 時求出的直徑上的路徑的邊權都變成 \(-1\) ,然後再求一遍直徑。令這條直徑為 \(l_2\) 答案就為 \(2*(n-1) - l_1 + 1 - l_2 + 1\)

化簡得 \(2n-l_1-l_2\)

這裏使用 樹形Dp 來求樹的直徑。

#include <iostream>
#include <cstdio>
#include <cstring>

const int MaxN = 1e5 + 5;

int N, K, L1, L2, Edge, Ans, T1, T2;
int Dp[MaxN], FST[MaxN], W[MaxN], F[MaxN], Vis[MaxN];

struct Linker
{
    int to, nxt;
    Linker(){}
    Linker(int x, int y)
    {
        to = y;
        nxt = FST[x];
    }
} E[MaxN << 1];

inline int read()
{
    register int x = 0;
    register char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch))
    {
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return x;
}

inline void AddEdge(int u, int v)
{
    E[++Edge] = Linker(u, v);
    FST[u] = Edge;
}

void DP(int x)
{
    Vis[x] = 1;
    for(int k = FST[x]; k; k = E[k].nxt)
    {
        int to = E[k].to, w = W[to] == 0 ? 1 : - 1;
        if(Vis[to]) continue; 
        DP(to);
        if(Dp[x] + Dp[to] + w > Ans)
        {
            Ans = Dp[x] + Dp[to] + w;
            T1 = F[x];
            T2 = to;
        }
        if(Dp[to] + w > Dp[x])
        {
            Dp[x] = Dp[to] + w;
            F[x] = to;
        }
    }
}

void paint(int x)
{
    if(!x) return;
    W[x] = 1;
    paint(F[x]);
}

int main()  
{
    N = read();
    K = read();
    for(int i = 1; i < N; ++i)
    {
        int u = read(), v = read();
        AddEdge(u, v);
        AddEdge(v, u);
    }
    DP(1);
    L1 = Ans;
    if(K == 1)
    {
        printf("%d\n", 2 * (N - 1) - L1 + 1);
        return 0;
    }
    else 
    {
        paint(T1);
        paint(T2);
        Ans = 0;
        memset(Dp, 0, sizeof(Dp));
        memset(F, 0, sizeof(F));
        memset(Vis, 0, sizeof(Vis));
        DP(1);
        L2 = Ans;
        printf("%d\n", 2 * N - L1 - L2);
    }
    return 0;
}

APIO2010 巡邏