zoukankan      html  css  js  c++  java
  • [NOIP2015]运输计划

    题意

    Here

    思考

    这题题意简要来讲就是:给定树上许多条链,求删掉一条边后,所有链的最大值最小是多少

    首先,各个点对间的距离可以用lca求出,主要问题是怎样考虑这个删边,删除一条边后会有以下两种情况:

    1. 取得最大值的点对间经过该边
    2. 取得最大值的点对间不经过该边

    这样就很难处理了,我们可以考虑二分答案,只考虑所有距离大于该值的点对,最后判断删边后所有大于该值的点对是否小于该值即可,删边当然是删掉所有大于该值的点对的公共边中的最大值啦。如何记录最大公共边?直接树上差分最后跑一边dfs就好~(不过最后吐槽一句:这题太卡常了,我现在luogu还有一个点被卡)

    代码

    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x * f;
    }
    const int M = 300030;
    const int N = 300030;
    struct node{
        int nxt, from, to, dis, LCA;
    }edge[M << 1], E[M];
    int head[N], num;
    void build(int from, int to, int dis){
        edge[++num].nxt = head[from];
        edge[num].to = to;
        edge[num].dis = dis;
        head[from] = num;
    }
    bool cmp(node a, node b){ return a.dis < b.dis; }
    int d[N], f[N][20], dis[N];
    void dfs(int u, int fa){
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(v == fa) continue;
            d[v] = d[u] + 1; f[v][0] = u; dis[v] = dis[u] + edge[i].dis;
            dfs(v, u);
        }
    }
    int lca(int u, int v){
        if(d[u] < d[v]) swap(u, v);
        for(int i=18; i>=0; i--) if(d[f[u][i]] >= d[v]) u = f[u][i];
        if(u == v) return u;
        for(int i=18; i>=0; i--) if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
        return f[u][0];
    }
    int n, m, val[N];
    void dfs2(int u, int fa){
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(v == fa) continue;
            dfs2(v, u);
            val[u] += val[v];
        }
    }
    bool check(int now){
        memset(val, 0, sizeof(val)); int js = 0;
        for(int i=1; i<=m; i++){
            if(E[i].dis > now) val[E[i].from] ++, val[E[i].to] ++, val[E[i].LCA] -= 2, js ++;
        }
        dfs2(1, 0);
        int nowdis = 0;
        for(int i=1; i<=n; i++){
            if(val[i] == js) nowdis = max(nowdis, dis[i] - dis[f[i][0]]);
        }
        for(int i=1; i<=m; i++){
            if(E[i].dis - nowdis <= now) continue;
            else return 0;
        }
        return 1;
    }
    int main(){
        n = read(); m = read();
        for(int i=1; i<=n-1; i++){
            int u = read(), v = read(), d = read();
            build(u, v, d); build(v, u, d);
        }
        d[1] = 1; dfs(1, 0);
        for(int j=1; j<=18; j++)
            for(int i=1; i<=n; i++) f[i][j] = f[f[i][j-1]][j-1];
        int MAX = 0;
        for(int i=1; i<=m; i++){
            E[i].from = read(), E[i].to = read();
            E[i].LCA = lca(E[i].from, E[i].to);
            E[i].dis = dis[E[i].from] + dis[E[i].to] - 2 * dis[E[i].LCA];
            MAX = max(MAX, E[i].dis);
        }
        int l = 0, r = MAX, ANS = 0;
        while(l <= r){
            int mid = (l + r) >> 1;
            if( check(mid) ){
                ANS = mid;
                r = mid - 1;
            }
            else l = mid + 1;
        }
        cout << ANS;
        return 0;
    }
    
    
    

    总结

    对于这一题,二分答案的原因是我们并不确定也不能直接算出最终的答案(因为有不同的情况),通过二分答案我们可以确定一个界限,方便我们求解。

  • 相关阅读:
    【微信小程序】数组操作
    iOS中html打开APP传参
    给radio加自己的样式(图片)
    TCP和IP的三次握手和第四次挥手
    什么是HTTP协议
    http和https的区别
    微信小程序-点击图片预览
    JAVASE
    thinkphp自学笔记
    前端必须掌握的30个CSS选择器
  • 原文地址:https://www.cnblogs.com/alecli/p/9911257.html
Copyright © 2011-2022 走看看