zoukankan      html  css  js  c++  java
  • 【题解】 NOIP2015 运输计划

      题目链接

      很明显的要用树上差分或者树链剖分,但是要求 将某一条边的权值归0后的最大路径最短是多少 ,就发人深思了。

      对于维护树上一条路径的大小,可以先用前缀和维护出从根到两个节点的路径大小和,再减去两点LCA的前缀和就可以了。我们可以先用倍增/树剖甚至是ST表求出LCA并预处理出每一条路径长,然后思考,我们怎么得知答案。

     

      容易想到个鬼二分答案,对于check答案是否正确的操作,我们可以记录下路径的最大值,并将所有大于当前答案的路径给更新到树上(用树上差分或者前缀和),再统计出  所有被更新了总更新路径条数  的边的最大值。用路径最大值减去后面这个最大值,若差小于等于答案,则可行,否则不可行。

      显然的证明:只要有一条大于当前答案的路径无法被某一条边给缩到小于答案以下,则答案不可行。

      代码:

      

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define maxn 300005
    
    int n,m,nex[2 * maxn],head[maxn],to[2 * maxn],edge[2 * maxn],tot,fa[maxn][35],sum[maxn],depth[maxn],tag[maxn],mt,cnt = 0,maxm,maxc,length[maxn],lc[maxn];
    struct road{
        int x,y;
    }rd[maxn];
    void add(int x,int y,int z) {
        to[++tot] = y; edge[tot] = z; nex[tot] = head[x]; head[x] = tot;
    }
    int lca(int x,int y) {
        if (depth[x] < depth[y]) std::swap(x,y);
        for (int i = mt;i >= 0;i--)
            if (depth[fa[x][i]] >= depth[y]) x = fa[x][i];
        if (x == y) return x;
        for (int i = mt;i >= 0;i--)
            if (fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i];
        return fa[x][0];
    }
    void dfs2(int x) {
        for (int i = head[x];i;i = nex[i]) {
            int y = to[i];
            if (y == fa[x][0]) continue;
            dfs2(y); tag[x] += tag[y];
        }//树上差分统计子树信息
    }
    int check(int x) {
        maxc = cnt = 0;
        for (int i = 1;i <= n;i++) tag[i] = 0;
        for (int i = 1;i <= m;i++) {
            if (length[i] > x) {
                tag[rd[i].x]++,tag[rd[i].y]++,tag[lc[i]] -= 2,cnt++;
            }//树上差分
        }
        dfs2(1);
        for (int i = 1;i <= n;i++) {
            if (tag[i] >= cnt) maxc = std::max(maxc,sum[i] - sum[fa[i][0]]);
        }
        if (maxm - maxc <= x) return 1;
        else return 0;
    }
    int divide() {
        int ans;
        int l = 0,r = maxm;
        while (l < r) {
            int mid = (l + r) / 2;
            if (check(mid)) r = mid;
            else l = mid + 1;
        }
        return l;
    }
    void dfs(int x,int f) {
        depth[x] = depth[f] + 1; fa[x][0] = f;
        for (int i = head[x];i;i = nex[i]) {
            int y = to[i];
            if (y == f) continue;
            sum[y] = sum[x] + edge[i];
            dfs(y,x);
        }
    }
    void deal() {
        for (int i = 1;(1 << (i - 1)) <= n;i++)
            for (int j = 1;j <= n;j++) {
                fa[j][i] = fa[fa[j][i - 1]][i - 1];
                mt = i;
            } //倍增预处理
    }
    int main() {
        scanf("%d%d",&n,&m);
        for (int i = 1;i < n;i++) {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        for (int i = 1;i <= m;i++) {
            scanf("%d%d",&rd[i].x,&rd[i].y);
        }
        dfs(1,0);
        deal();
        for (int i = 1;i <= m;i++) {
            int p = lca(rd[i].x,rd[i].y);
            lc[i] = p;
            length[i] = sum[rd[i].x] + sum[rd[i].y] - 2 * sum[p];
            maxm = std::max(maxm,length[i]);//统计出每条路径的LCA、长度、以及最长路径
        }
        printf("%d
    ",divide());
        return 0;
    }
  • 相关阅读:
    spring-mybatis 事物配置 execution表达式含义
    微信内置浏览器缓存导致链接无法多次访问
    linux学习记录-------解决复制的虚拟机,无法同时上网
    mybatis-select-insert-update-delete
    tomcat 端口被占用
    EFCodeFirst安装失败(包括EntityFrameWork安装),这样解决。。。
    数组的一些操作
    《Java技术》第三次作业--面向对象——继承、抽象类、接口
    java第二次作业
    《Java技术》第一次作业
  • 原文地址:https://www.cnblogs.com/Illusions/p/13935505.html
Copyright © 2011-2022 走看看