zoukankan      html  css  js  c++  java
  • BZOJ4326: NOIP2015 运输计划

    从题解里看到了二分才想到二分

    题意为:给出一棵树和一些路线,要求你选树上一条边边权变为0后,路线中最大值最小

    显然答案有单调性,二分答案

    将所有长度超过 mid 的路径在树上标记出来,找出一条被所有的标记路径覆盖的边,当前答案合法条件为:max_path - maxlen <= mid

    显然上边的操作可以树上差分,预处理每条路径端点的 lca 即可做到 O(n) 判断

    这个 O(n) 大概是 2n ,卡卡常就好了


    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cstdio>
    using namespace std;
    
    const int MAXN = 300005;
    
    struct EDGE{
      int nxt, to, val;
      EDGE(int NXT = 0, int TO = 0, int VAL = 0) {nxt = NXT; to = TO; val = VAL;}
    }edge[MAXN << 1];
    struct QUE{
      int x, y, lca, dst;
    }que[MAXN];
    int n, m, totedge, mxl, mnl = 0x7fffffff;
    int head[MAXN], dst[MAXN], tag[MAXN], top[MAXN];
    int dep[MAXN], siz[MAXN], son[MAXN], fa[MAXN];
    
    inline int rd() {
      register int x = 0;
      register char c = getchar();
      while(!isdigit(c)) c = getchar();
      while(isdigit(c)) {
        x = x * 10 + (c ^ 48);
        c = getchar();
      }
      return x;
    }
    inline int mx(int x, int y) {
      return (x > y ? x : y);
    }
    inline int mn(int x, int y) {
      return (x > y ? y : x);
    }
    void gfs(int x) {
      siz[x] = 1;
      for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != fa[x]) {
        int y = edge[i].to;
        dep[y] = dep[x] + 1;
        dst[y] = dst[x] + edge[i].val;
        fa[y] = x;
        gfs(y);
        siz[x] += siz[y];
        if(siz[y] > siz[son[x]]) son[x] = y;
      }
      return;
    }
    void ifs(int x) {
      if(!top[x]) top[x] = x;
      if(son[x]) {
        top[son[x]] = top[x];
        ifs(son[x]);
      }
      for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != son[x] && edge[i].to != fa[x]) ifs(edge[i].to);
      return;
    }
    inline int lca(int x, int y) {
      while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
      }
      return (dep[x] > dep[y] ? y : x);
    }
    int dfs(int x, int tot, int frm) {
      int maxlen = 0;
      for(int i = head[x]; i; i = edge[i].nxt) if(fa[x] != edge[i].to) {
          maxlen = max(maxlen, dfs(edge[i].to, tot, i));
          tag[x] += tag[edge[i].to];
      }
      return (tag[x] == tot) ? (mx(maxlen, edge[frm].val)) : maxlen;
    }
    inline bool chk(int mid) {
      register int tot = 0, maxlen = 0;
      register bool extra = false;
      for(int i = 1; i <= n; ++i) tag[i] = 0;
      for(int i = 1; i <= m; ++i) {
        if(que[i].dst > mid) {
          maxlen = mx(maxlen,que[i].dst);
          ++tot;
          ++tag[que[i].x]; ++tag[que[i].y];
          tag[que[i].lca] -= 2;
          extra = true;
        }
      }
      if(!extra) return true;
      return (maxlen - dfs(1, tot, 0) <= mid);
    }
    inline void hfs(int l, int r) {
      int mid = 0, ans = 0;
      while(l < r) {
        mid = ((l + r) >> 1);
        if(chk(mid)) {
          ans = mid;
          r = mid;
        }
        else l = mid + 1;
      }
      printf("%d
    ", ans);
      return;
    }
    
    int main() {
      //  freopen("testdata1.in", "r", stdin);
      n = rd(); m = rd();
      register int xx, yy, vv, tmp, N;
      tmp = (n - 1) & 1; N = n - 1 - tmp;
     //printf("tmp = %d, N = %d
    ", tmp, N);
      for(int i = 1; i <= N; i += 2) {
      //	printf("i = %d
    ", i);
      //	printf("totedge = %d
    ", totedge);
        xx = rd(); yy = rd(); vv = rd();
        mnl = mn(mnl,vv);
    	edge[++totedge] = EDGE(head[xx], yy, vv);
    	head[xx] = totedge;
    	edge[++totedge] = EDGE(head[yy], xx, vv);
    	head[yy] = totedge;
        xx = rd(); yy = rd(); vv = rd();
        mnl = mn(mnl,vv);
    	edge[++totedge] = EDGE(head[xx], yy, vv);
    	head[xx] = totedge;
    	edge[++totedge] = EDGE(head[yy], xx, vv);
    	head[yy] = totedge;
    //	printf("totedge = %d
    ", totedge);
      }
      for(int i = 1; i <= tmp; ++i) {
        xx = rd(); yy = rd(); vv = rd();
        mnl = mn(mnl,vv);
    	edge[++totedge] = EDGE(head[xx], yy, vv);
    	head[xx] = totedge;
    	edge[++totedge] = EDGE(head[yy], xx, vv);
    	head[yy] = totedge;
      }
      dst[1] = 0; dep[1] = 1;
      gfs(1);
      ifs(1);
      for(int i = 1; i <= m; ++i) {
        que[i].x = rd(); que[i].y = rd();
        que[i].lca = lca(que[i].x, que[i].y);
        que[i].dst = dst[que[i].x] + dst[que[i].y] - (dst[que[i].lca] << 1);
        mxl = mx(mxl,que[i].dst);
      }
      hfs(mnl, mxl);
      return 0;
    }
    

      

    禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载 ,用户转载请注明出处:https://www.cnblogs.com/xcysblog/
  • 相关阅读:
    UVa 1354 天平难题 (枚举二叉树)
    广西邀请赛总结
    UVa 12118 检查员的难题 (dfs判连通, 构造欧拉通路)
    UVA
    Uva 127 "Accordian" Patience (模拟)
    UVA 10539 Almost Prime Numbers( 素数因子)
    HDU 1272 小希的迷宫(并查集)
    HDU 1213 How Many Tables (并查集)
    POJ 2236 Wireless Network(并查集)
    HDU 1233 还是畅通工程 ( Kruskal或Prim)
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9570632.html
Copyright © 2011-2022 走看看