NOIP 2015

NOIP 2015

2日目

T3輸送計画

問題の意味:ある\(N- \)の長さを有する各側は、mはパスツリー与えられる木ポイントは、あなたがエッジを選択することができ、その長さは0に変更され、これは最長パスMを必要最短のは何ですか

\(N、M \ル3 \ times10。5 ^ \) 以下の辺の長さ\(\ 1000)

ソリューション:

\(1 \)バイナリ答え、オーバーランの開始交差点の長さ、交点が0である場合、溶液、または交差点の最長辺から選択

\(2 \)木の交差点差(-1エンドポイント$ \(、\) LCAの$ + 2)

時間の複雑さ:\(O(nlog ^ 2n個)\)

\(1 \)それはのパスの両端に見つけられなければならない、交差点二十から二パスを考える\(4 \) LCA LCAの(タイトルがそうすることができ、最も深い2ヶ月でのパスだけでなく、他の問題を検討\(4 \)のような)オーバーラップLCA番目。

\(2 \)が交差が空であるか、または最長の長さが十分ではありません、そして出力にあればそう、そして答えは列挙するために、交差点に続いて、二分法は非常に有用ではありません、あなたは降順側に置くことができたんします答えます。それはすることができます(RMQ \)\最適化リクエスト\(LCA \を)

時間計算:\(O(nlogn)\)マジックとすることができる多数の方法によって聞か(RMQ \)\最適化する前処理\(O(N)\) 総時間の複雑さに到達\(O( N)\)

最初のために\(O(nlog ^ 2n個) \) ソリューションは、我々は時間の複雑さを軽減するためにされるように、LCAに直接各ペアを前処理してもよい発見した\(O(nlogn)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 300100
#define RE register 
int n, m;
int st[maxn], ed[maxn], len[maxn];
int fir[maxn], nxt[maxn * 2], vv[maxn * 2], edge[maxn * 2];
int tot = 0;
int read()
{
    int ret = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = getchar();
    }
    return ret;
}
void add(int u, int v, int w)
{
    nxt[++tot] = fir[u];
    fir[u] = tot;
    vv[tot] = v;
    edge[tot] = w;
}
int dep[maxn], f[maxn][25], g[maxn][25];
void Deal_first(int u, int fa)
{
 //   printf("u = %d fa = %d\n", u, fa);
    dep[u] = dep[fa] + 1;
    for(RE int i = 0; i <= 19; i++)
    {
        f[u][i + 1] = f[f[u][i]][i];
        g[u][i + 1] = g[u][i] + g[f[u][i]][i];
    }
    for(RE int i = fir[u]; i; i = nxt[i])
    {
        int v = vv[i];
        if(v == fa) continue;
        f[v][0] = u;
        g[v][0] = edge[i];
        Deal_first(v, u);
    }
}
int LCA(int x, int y, int &dis)
{
    if(dep[x] < dep[y]) swap(x, y);
    for(RE int i = 20; i >= 0; i--)
    {
        if(dep[f[x][i]] >= dep[y])
        {
            dis += g[x][i];
    //        printf("g[x][i] = %d\n", g[x][i]);
            x = f[x][i];
        }
   //     printf("x = %d y = %d\n", x, y);
        if(x == y)
        {
            return x;
        }
    }
    for(RE int i = 20; i >= 0; i--)
    {
        if(f[x][i] != f[y][i])
        {
            dis += g[x][i];
            dis += g[y][i];
            x = f[x][i];
            y = f[y][i];
    //        printf("x = %d y = %d\n", x, y);
        }
    }
    dis += (g[x][0] + g[y][0]);
    return f[x][0];
}
int val[maxn], dp[maxn * 2], from[maxn], lc[maxn];
void dfs(int u, int fa)
{
    dp[from[u]] += val[u];
    for(RE int i = fir[u]; i; i = nxt[i])
    {
        int v = vv[i];
        if(v == fa) continue;
        from[v] = i;
        dfs(v, u);
        dp[from[u]] += dp[from[v]];
    }
}
int lenth;
int check(int x)
{
    memset(val, 0, sizeof(val));
    memset(dp, 0, sizeof(dp));
    int cnt = 0;
    for(RE int i = 1; i <= m; i++)
    {
        if(len[i] > x)
        {
            cnt++;
            int u = st[i], v = ed[i];
            int xx = 0;
            val[u] += 1; val[v] += 1;
            val[lc[i]] -= 2;
        }
   //     else break;
    }
    dfs(1, 0);
    int maxx = -1;
    for(RE int i = 1; i <= tot; i++)
    {
    //    printf("dp[%d] = %d ", i, dp[i]);
        if(dp[i] >= cnt)
        {
            maxx = max(maxx, edge[i]);
        }
    }
   // printf("\n");
   // printf("x = %d cnt = %d maxx = %d\n", x, cnt, maxx);
    if(!cnt) return 1;
    if(maxx == -1 || lenth - maxx > x) return 0;
    return 1;
}
bool cmp(int x, int y)
{
    return x > y;
}
int main()
{
    n = read(); m = read();
    for(RE int i = 1; i < n; i++)
    {
        int u, v, w;
        u = read(); v = read(); w = read();
        add(u, v, w); add(v, u, w);
    }
    for(RE int i = 1; i <= m; i++)
    {
        st[i] = read(); ed[i] = read();
    }
    Deal_first(1, 0);
    for(RE int i = 1; i <= m; i++)
    {
        int dis = 0;
        int fa = LCA(st[i], ed[i], dis);
        len[i] = dis; lenth = max(lenth, len[i]);
        lc[i] = fa;
    //    printf("u = %d v = %d fa = %d\n", st[i], ed[i], fa);
        //len[i] = dep[st[i]] + dep[ed[i]] - dep[LCA(st[i], ed[i])] * 2;
    }
   // sort(len + 1, len + m + 1, cmp);
   // for(int i = 1; i <= m; i++) printf("len[%d] = %d\n", i, len[i]);
    int l = 0, r = 3e8, ans = 0;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(check(mid) == 1)
        {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    printf("%d\n", ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/Akaina/p/11649446.html