[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章