zoukankan      html  css  js  c++  java
  • 【NOIP2015提高组】运输计划

    https://daniu.luogu.org/problem/show?pid=2680

    使完成所有运输计划的时间最短,也就是使时间最长的运输计划耗时最短。最大值最小问题考虑用二分答案,每次check(mid)检查时间最长的运输计划耗时是否小于等于mid,二分出使得check(mid)==true的最小mid值。

    check函数怎么写是本题的难点。
    耗时小于mid的运输计划不会影响check的结果。耗时大于mid的运输计划肯定需要改造他们的共同边才有可能使它们耗时都小于mid,而有多条共同边的时候肯定是改权值最大的更合算。如果改造了这条边可以使得原来时间最长的运输计划耗时也小于mid,则返回true,否则返回false。

    所以读入数据时需要预处理下每个运输计划的耗时。

    问题就在于怎么判断是否有公共边了。首先无根树转有根树,为了方便判断把边的权值放到子结点上。
    可以用树剖+线段树把每一条路径上经过的所有点(除LCA)计数加一,然后看计数最大的点。但是更快更方便的方法是树上差分——对于每一条路径给两端的结点计数加1,给LCA计数减2。统计完之后做一遍树上前缀和,还可以在这个过程顺便求出计数最多的点。

    注意这题卡常数非常厉害,记得用上快速读入、链式前向星、启发式合并+路径压缩的并查集。

    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <vector>
    #define maxn 300005
    using namespace std;
    void scan(int &x)
    {
        x = 0;
        char c;
        bool flag = false;
        while (!isdigit(c = getchar()))
        {
            if (c == '-')
                flag = true;
            if (c == EOF)
                return;
        }
        do
            x = x * 10 + c - '0';
        while (isdigit(c = getchar()));
        if (flag)
            x = -x;
    }
    
    int n, m;
    struct edge
    {
        int next, to, weight;
    } edges[maxn * 2];
    int head[maxn], ecnt = 1;
    void add_edge(int u, int v, int w)
    {
        edges[ecnt].to = v;
        edges[ecnt].weight = w;
        edges[ecnt].next = head[u];
        head[u] = ecnt++;
    
        edges[ecnt].to = u;
        edges[ecnt].weight = w;
        edges[ecnt].next = head[v];
        head[v] = ecnt++;
    }
    int weight[maxn], parent[maxn], length[maxn];
    void build_tree(int v, int fr, int wei)
    {
        parent[v] = fr;
        weight[v] = wei;
        length[v] = length[fr] + wei;
        for (int i = head[v]; i; i = edges[i].next)
        {
            if (edges[i].to != fr)
            {
                build_tree(edges[i].to, v, edges[i].weight);
            }
        }
    }
    
    namespace djs
    {
    int djs_parent[maxn];
    void init()
    {
        for (int i = 1; i <= n; i++)
            djs_parent[i] = -1;
    }
    int find(int x)
    {
        if (djs_parent[x] < 0)
            return x;
        else
            return djs_parent[x] = find(djs_parent[x]);
    }
    void merge(int x, int y)
    {
        x = find(x);
        y = find(y);
        djs_parent[y] = x;
    }
    }
    int from[maxn], to[maxn], cost[maxn], lca[maxn];
    vector<int> query_index[maxn];
    bool visited[maxn];
    void get_lca(int v)
    {
        for (int i = head[v]; i; i = edges[i].next)
        {
            int w = edges[i].to;
            if (w != parent[v])
            {
                get_lca(w);
                djs::merge(v, w);
            }
        }
        visited[v] = true;
    
        for (int i = 0; i < query_index[v].size(); i++)
        {
            int q = query_index[v][i];
            int w = (from[q] == v) ? to[q] : from[q];
            if (visited[w])
                lca[q] = djs::find(w);
        }
    }
    
    int mark[maxn], maxmark;
    void markdown(int i)
    {
        mark[from[i]]++;
        mark[to[i]]++;
        mark[lca[i]] -= 2;
    }
    void push_down(int v)
    {
        for (int i = head[v]; i; i = edges[i].next)
        {
            int w = edges[i].to;
            if (w != parent[v])
            {
                push_down(w);
                mark[v] += mark[w];
            }
        }
        if (mark[v] > mark[maxmark])
            maxmark = v;
        else if (mark[v] == mark[maxmark] && weight[v] > weight[maxmark])
            maxmark = v;
    }
    bool check(int k)
    {
        for (int i = 1; i <= n; i++)
            mark[i] = 0;
        int maxcost = 0;
        int cnt = 0;
        for (int i = 1; i <= m; i++)
        {
            if (cost[i] > k)
            {
                cnt++;
                markdown(i);
                maxcost = max(maxcost, cost[i]);
            }
        }
        if (cnt == 0)
            return true;
        maxmark = 0;
        push_down(1);
        if (mark[maxmark] >= cnt && maxcost - weight[maxmark] <= k)
            return true;
        else
            return false;
    }
    int main()
    {
        scan(n);
        scan(m);
        int a, b, c;
        for (int i = 1; i < n; i++)
        {
            scan(a);
            scan(b);
            scan(c);
            add_edge(a, b, c);
        }
        build_tree(1, 0, 0);
        for (int i = 1; i <= m; i++)
        {
            scan(from[i]);
            scan(to[i]);
            query_index[from[i]].push_back(i);
            query_index[to[i]].push_back(i);
        }
        djs::init();
        get_lca(1);
        for (int i = 1; i <= m; i++)
        {
            cost[i] = length[from[i]] + length[to[i]] - 2 * length[lca[i]];
        }
    
        int l = 0, r = 1000 * maxn, mid;
        while (l < r)
        {
            mid = (l + r) / 2;
            if (check(mid))
                r = mid;
            else
                l = mid + 1;
        }
        cout << l << endl;
        return 0;
    }
  • 相关阅读:
    27 Spring Cloud Feign整合Hystrix实现容错处理
    26 Spring Cloud使用Hystrix实现容错处理
    25 Spring Cloud Hystrix缓存与合并请求
    24 Spring Cloud Hystrix资源隔离策略(线程、信号量)
    23 Spring Cloud Hystrix(熔断器)介绍及使用
    22 Spring Cloud Feign的自定义配置及使用
    21 Spring Cloud使用Feign调用服务接口
    20 Spring Cloud Ribbon配置详解
    19 Spring Cloud Ribbon自定义负载均衡策略
    18 Spring Cloud Ribbon负载均衡策略介绍
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7530665.html
Copyright © 2011-2022 走看看