• [NOIp2015]运输计划


    Description

    BZOJ4326
    Luogu2680
    给定一棵树,和若干路径,求使一条边长度变为0后,最长路径的最小值。

    Solution

    链上的情况可以求出路径的交(差分或者运用前缀和的思想求“前缀交”),然后二分答案统计即可。
    推广到树上,首先可以树上差分,然后二分答案统计,也可以尝试树上路径求“前缀交”。

    Code

    差分版:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    const int N = 3e5 + 10;
    const int M = 2*N + 10;
    
    int hd[N], to[M], nxt[M], w[M], cnt;
    int dep[N], fa[N], sz[N], son[N];
    int top[N], id[N], rnk[N], tot;
    int n, m, mxd, mxe, fck;
    int flag[N], dis[N];
    int px[N], py[N], plca[N], pd[N];
    
    void adde(int x, int y, int z) {
        cnt++;
        to[cnt] = y; nxt[cnt] = hd[x]; w[cnt] = z;
        hd[x] = cnt;
    }
    
    int dfs1(int x, int f) {
        fa[x] = f;
        dep[x] = dep[f] + 1;
        sz[x] = 1;
        for (int i = hd[x]; i; i = nxt[i]) if (to[i] != f) {
            dis[to[i]] = dis[x] + w[i];
            sz[x] += dfs1(to[i], x);
            if (sz[to[i]] > sz[son[x]])
                son[x] = to[i];
        }
        return sz[x];
    }
    
    void dfs2(int x, int f) {
        top[x] = f;
        id[x] = tot++;
        rnk[tot] = x;
        if (!son[x]) return;
        dfs2(son[x], f);
        for (int i = hd[x]; i; i = nxt[i]) if (to[i] != fa[x] && to[i] != son[x]) {
            dfs2(to[i], to[i]);
        }
    }
    
    int lca(int x, int y) {
        while (top[x] != top[y]) {
            if (dep[top[x]] > dep[top[y]]) x = fa[top[x]];
            else y = fa[top[y]];
        }
        return dep[x] > dep[y] ? y : x;
    }
    
    bool check(int x) {
        fck = 0; memset(flag, 0, sizeof flag);
        for (int i = 1; i <= m; ++i) if (pd[i] > x) {
            flag[px[i]]++;
            flag[py[i]]++;
            flag[plca[i]] -= 2;
            fck++;
        }
        for (int i = n; i; --i) {
            int &j = rnk[i];
            flag[fa[j]] += flag[j];
            if (flag[j] == fck) {
                int fe = dis[j] - dis[fa[j]];
            	if (mxd - fe <= x) return true;
            }
        }
        return false;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1, x, y, z; i < n; ++i) {
            scanf("%d%d%d", &x, &y, &z);
            adde(x, y, z);
            adde(y, x, z);
            mxe = std::max(mxe, z);
        }
        dfs1(1, 0);
        dfs2(1, 1);
        for (int i = 1; i <= m; ++i) {
            scanf("%d%d", &px[i], &py[i]);
            plca[i] = lca(px[i], py[i]); 
            pd[i] = dis[px[i]] + dis[py[i]] - 2 * dis[plca[i]];
            mxd = std::max(mxd, pd[i]);
        }
        int L = mxd - mxe, R = mxd;
        while (L < R) {
            int mid = (L + R) >> 1;
            if (check(mid)) {
                R = mid;
            } else {
                L = mid+1;
            }
        }
        printf("%d
    ", L);
        return 0;
    }
    

    TODO: “前缀交”版本

  • 相关阅读:
    WF4.0 基础 InvokeMethod 调用方法
    MySQL数据库表名、列名、别名区分大小写的问题
    客户端调用Web服务
    something about Socket
    C#参数传递
    学习内容
    About HttpContext
    Best Sequence [POJ1699] TSPDP
    优先队列
    Watermelon Full of Water [ZOJ 4778]
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/noip201523.html
Copyright © 2020-2023  润新知