[codeforces] 1004 E. Sonya and Ice Cream

[codeforces] 1004 E. Sonya and Ice Cream

題目鏈接:

E. Sonya and Ice Cream

題目大意:

給一個n(1n105) 個點的樹,每一條邊有一個長度l(1l104) , 現在讓你找出一最長長度爲k(1kn) 條鏈, 使得鏈外的點到鏈上的最大距離最小能多小。

思路:

剛開始思路跑偏了, 忘記了題目中給定要求是找出一條鏈, 我以爲最壞情況可以找出一棵子樹。

首先可以確定的是要求出一條最長鏈, 對於鏈上的每一個點求出這個點不在鏈上的最長向外延伸的長度, 那麼我們要維護一個長度爲k的鏈, 對於鏈上的點就分爲兩種情況。

  1. 最長鏈上的點在所選鏈的範圍內, 那麼他對答案產生的影響就是這個點向外延伸的長度
  2. 每次都求出最長鏈兩端沒有被選擇的長度。

最長鏈中選擇長度爲k的子鏈, 兩邊的長度很好維護, 需要考慮的是被選中的這k個點向外延伸的最長長度, 這個時候就可以用單調隊列維護。

整個題的思路就是先跑出最長鏈, 把鏈上的所有點以及每個點到鏈頭的長度維護出來。

之後再對鏈上的每一個點求出向鏈外延伸的最長長度。

之後便是掃一遍鏈上每一個點, 使用單調隊列維護區間內的向外延伸最長長度。

AC代碼

/********************************************
 *Author*        :ZZZZone
 *Created Time*  : 2018年07月09日 星期一 20時41分46秒
 * Ended  Time*  : 2018年07月09日 星期一 20時58分57秒
*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;

inline void OPEN(string s){
    freopen((s + ".in").c_str(), "r", stdin);
    freopen((s + ".out").c_str(), "w", stdout);
}

const int MAXN = 1e5;

int n, k;
vector<PII> edge[MAXN+5];
int dis[MAXN+5], pre[MAXN+5];
bool vis[MAXN+5];

void Init(){
    scanf("%d %d", &n, &k);
    for(int i = 1; i < n; i++){
        int u ,v, c;
        scanf("%d %d %d", &u, &v, &c);
        edge[u].push_back(PII(v, c));
        edge[v].push_back(PII(u, c));
    }
}

void Dfs(int u, int fa, int& Max_len){
    Max_len = max(Max_len, dis[u]);
    pre[u] = fa;
    for(int i = 0; i < edge[u].size(); i++){
        int v = edge[u][i].first;
        int cost = edge[u][i].second;
        if(vis[v] || v == fa) continue;
        dis[v] = dis[u] + cost;
        Dfs(v, u, Max_len);
    }
}

void Solve(){
    dis[1] = 0;
    int Max_len = 0;
    Dfs(1, 0, Max_len);
    int st = 1, ed = 1;
    for(int i = 1; i <= n; i++){
        if(dis[i] > dis[st]) st = i;
    }
    dis[st] = 0;
    Dfs(st, 0, Max_len);
    for(int i = 1; i <= n; i++){
        if(dis[i] > dis[ed]) ed = i;
    }
    vector<int> dia, len, dep;
    while(ed){
        dia.push_back(ed);
        len.push_back(dis[ed]);
        vis[ed] = true;
        ed = pre[ed];
    }
    reverse(dia.begin(), dia.end());
    reverse(len.begin(), len.end());
    int tot = (int)dia.size();
    k = min(k ,tot);
    for(int i = 0; i < tot; i++){
        dis[dia[i]] = Max_len = 0;
        Dfs(dia[i], 0, Max_len);
        dep.push_back(Max_len);
    }
    int res = 1 << 30;
    deque<PII> dque;// 雙端隊列實現單調隊列
    for(int i = 0, j = 0; i + k <= tot; i++){
        while(j < i + k){
            while(!dque.empty() && dque.back().first < dep[j]){
                dque.pop_back();
            }
            dque.push_back(PII(dep[j], j));
            j++;
        }
        while(dque.front().second < i) dque.pop_front();
        res = min(res , max(len[i], max(len.back() - len[i+k-1], dque.front().first)));
    }
    printf("%d\n", res);
}

int main()
{
    Init();
    Solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章